specweave 0.28.57 β 0.28.61
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/bin/specweave.js +36 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +13 -1
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/jobs.d.ts +20 -0
- package/dist/src/cli/commands/jobs.d.ts.map +1 -0
- package/dist/src/cli/commands/jobs.js +448 -0
- package/dist/src/cli/commands/jobs.js.map +1 -0
- package/dist/src/cli/helpers/init/ado-repo-cloning.d.ts +32 -0
- package/dist/src/cli/helpers/init/ado-repo-cloning.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/ado-repo-cloning.js +161 -0
- package/dist/src/cli/helpers/init/ado-repo-cloning.js.map +1 -0
- package/dist/src/cli/helpers/init/external-import.d.ts +18 -1
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/external-import.js +61 -21
- package/dist/src/cli/helpers/init/external-import.js.map +1 -1
- package/dist/src/cli/helpers/selection-strategy.d.ts +28 -0
- package/dist/src/cli/helpers/selection-strategy.d.ts.map +1 -1
- package/dist/src/cli/helpers/selection-strategy.js +48 -0
- package/dist/src/cli/helpers/selection-strategy.js.map +1 -1
- package/dist/src/cli/workers/import-worker.d.ts +18 -0
- package/dist/src/cli/workers/import-worker.d.ts.map +1 -0
- package/dist/src/cli/workers/import-worker.js +268 -0
- package/dist/src/cli/workers/import-worker.js.map +1 -0
- package/dist/src/core/background/index.d.ts +8 -0
- package/dist/src/core/background/index.d.ts.map +1 -1
- package/dist/src/core/background/index.js +8 -0
- package/dist/src/core/background/index.js.map +1 -1
- package/dist/src/core/background/job-launcher.d.ts +54 -0
- package/dist/src/core/background/job-launcher.d.ts.map +1 -0
- package/dist/src/core/background/job-launcher.js +206 -0
- package/dist/src/core/background/job-launcher.js.map +1 -0
- package/dist/src/core/repo-structure/providers/azure-devops-provider.d.ts +15 -0
- package/dist/src/core/repo-structure/providers/azure-devops-provider.d.ts.map +1 -1
- package/dist/src/core/repo-structure/providers/azure-devops-provider.js +56 -0
- package/dist/src/core/repo-structure/providers/azure-devops-provider.js.map +1 -1
- package/dist/src/importers/ado-importer.d.ts +7 -1
- package/dist/src/importers/ado-importer.d.ts.map +1 -1
- package/dist/src/importers/ado-importer.js +108 -61
- package/dist/src/importers/ado-importer.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/commands/specweave-jobs.md +133 -29
- package/plugins/specweave-ado/commands/specweave-ado-clone-repos.md +379 -0
- package/plugins/specweave-release/commands/specweave-release-npm.md +51 -14
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: specweave:jobs
|
|
3
|
-
description: Monitor background jobs (repo cloning, issue import). Shows progress, allows pause/resume.
|
|
4
|
-
usage: /specweave:jobs [--active|--all|--id <job-id>] [--resume <job-id>]
|
|
3
|
+
description: Monitor background jobs (repo cloning, issue import). Shows progress, allows pause/resume/kill.
|
|
4
|
+
usage: /specweave:jobs [--active|--all|--id <job-id>] [--resume <job-id>] [--kill <job-id>] [--follow <job-id>] [--logs <job-id>]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Background Jobs Monitor
|
|
@@ -17,6 +17,25 @@ Monitor and manage long-running background operations:
|
|
|
17
17
|
- **Issue import** (10K+ items from GitHub/JIRA/ADO)
|
|
18
18
|
- **External sync** operations
|
|
19
19
|
|
|
20
|
+
**ASYNC ARCHITECTURE (2025-12-01)**:
|
|
21
|
+
- Jobs run as **detached processes** that survive terminal close
|
|
22
|
+
- Progress tracked via filesystem (`.specweave/state/jobs/`)
|
|
23
|
+
- Can check status anytime with `/specweave:jobs`
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Command Options
|
|
28
|
+
|
|
29
|
+
| Option | Description |
|
|
30
|
+
|--------|-------------|
|
|
31
|
+
| (none) | Show active jobs |
|
|
32
|
+
| `--all` | Show all jobs (including completed) |
|
|
33
|
+
| `--id <jobId>` | Show details for specific job |
|
|
34
|
+
| `--follow <jobId>` | Follow job progress in real-time |
|
|
35
|
+
| `--logs <jobId>` | Show worker log output |
|
|
36
|
+
| `--resume <jobId>` | Resume paused job |
|
|
37
|
+
| `--kill <jobId>` | Kill running background job |
|
|
38
|
+
|
|
20
39
|
---
|
|
21
40
|
|
|
22
41
|
## Check Job Status
|
|
@@ -26,6 +45,12 @@ Read the background jobs state file and display status:
|
|
|
26
45
|
```bash
|
|
27
46
|
# Find and read the state file
|
|
28
47
|
STATE_FILE=".specweave/state/background-jobs.json"
|
|
48
|
+
|
|
49
|
+
# Also check job-specific files:
|
|
50
|
+
# .specweave/state/jobs/<jobId>/config.json - Job configuration
|
|
51
|
+
# .specweave/state/jobs/<jobId>/worker.pid - Process ID (if running)
|
|
52
|
+
# .specweave/state/jobs/<jobId>/worker.log - Worker output log
|
|
53
|
+
# .specweave/state/jobs/<jobId>/result.json - Results (when complete)
|
|
29
54
|
```
|
|
30
55
|
|
|
31
56
|
### Display Format
|
|
@@ -34,25 +59,28 @@ STATE_FILE=".specweave/state/background-jobs.json"
|
|
|
34
59
|
π Background Jobs
|
|
35
60
|
|
|
36
61
|
π Running (1):
|
|
37
|
-
[abc12345]
|
|
38
|
-
Progress: 2/
|
|
39
|
-
Rate:
|
|
40
|
-
Started: 2 mins ago
|
|
62
|
+
[abc12345] import-issues (ADO)
|
|
63
|
+
Progress: 2,500/10,000 (25%)
|
|
64
|
+
Rate: 15.2/s | ETA: ~8m 14s
|
|
65
|
+
PID: 45678 | Started: 2 mins ago
|
|
41
66
|
|
|
42
67
|
βΈοΈ Paused (1):
|
|
43
68
|
[def67890] import-issues (GitHub)
|
|
44
69
|
Progress: 1,234/10,000 (12%)
|
|
45
|
-
Reason: Rate limited
|
|
70
|
+
Reason: Rate limited (resumes in 45s)
|
|
46
71
|
Resume: /specweave:jobs --resume def67890
|
|
47
72
|
|
|
48
73
|
β
Completed (2):
|
|
49
|
-
[ghi11111]
|
|
50
|
-
[jkl22222]
|
|
74
|
+
[ghi11111] import-issues - 4,500 items - 5 mins ago
|
|
75
|
+
[jkl22222] clone-repos - 4/4 repos - 1 hour ago
|
|
51
76
|
|
|
52
77
|
π‘ Commands:
|
|
53
|
-
/specweave:jobs --id abc12345
|
|
54
|
-
/specweave:jobs --
|
|
55
|
-
/specweave:jobs --
|
|
78
|
+
/specweave:jobs --id abc12345 β Details for specific job
|
|
79
|
+
/specweave:jobs --follow abc12345 β Follow progress live
|
|
80
|
+
/specweave:jobs --logs abc12345 β View worker logs
|
|
81
|
+
/specweave:jobs --resume def67890 β Resume paused job
|
|
82
|
+
/specweave:jobs --kill abc12345 β Kill running job
|
|
83
|
+
/specweave:jobs --all β Show all jobs (including old)
|
|
56
84
|
```
|
|
57
85
|
|
|
58
86
|
---
|
|
@@ -66,32 +94,92 @@ STATE_FILE=".specweave/state/background-jobs.json"
|
|
|
66
94
|
|
|
67
95
|
π¦ Job Details: abc12345
|
|
68
96
|
|
|
69
|
-
Type:
|
|
97
|
+
Type: import-issues
|
|
70
98
|
Status: running
|
|
99
|
+
Provider: ADO
|
|
100
|
+
PID: 45678
|
|
101
|
+
|
|
71
102
|
Started: 2024-01-15 10:30:00
|
|
72
103
|
Updated: 2024-01-15 10:32:15
|
|
73
104
|
|
|
74
|
-
Progress: 2/
|
|
75
|
-
Current:
|
|
76
|
-
Rate:
|
|
77
|
-
ETA: ~
|
|
105
|
+
Progress: 2,500/10,000 (25%)
|
|
106
|
+
Current: OlySense\Core-Operations
|
|
107
|
+
Rate: 15.2 items/sec
|
|
108
|
+
ETA: ~8 minutes
|
|
109
|
+
|
|
110
|
+
Files:
|
|
111
|
+
Config: .specweave/state/jobs/abc12345/config.json
|
|
112
|
+
Logs: .specweave/state/jobs/abc12345/worker.log
|
|
113
|
+
PID: .specweave/state/jobs/abc12345/worker.pid
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Follow Job Progress Live
|
|
117
|
+
|
|
118
|
+
Watch job progress in real-time (like `tail -f`):
|
|
78
119
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
β
sw-meeting-cost-shared
|
|
120
|
+
```
|
|
121
|
+
/specweave:jobs --follow abc12345
|
|
82
122
|
|
|
83
|
-
|
|
84
|
-
β³ sw-meeting-cost-be
|
|
85
|
-
β³ sw-meeting-cost
|
|
123
|
+
π¦ Following job abc12345 (Ctrl+C to stop)
|
|
86
124
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
125
|
+
[10:30:15] Progress: 2,500/10,000 (25%) - OlySense\Core-Operations
|
|
126
|
+
[10:30:16] Progress: 2,520/10,000 (25%) - OlySense\Core-Operations
|
|
127
|
+
[10:30:17] Progress: 2,545/10,000 (25%) - OlySense\AI-Platform
|
|
128
|
+
[10:30:18] Progress: 2,570/10,000 (26%) - OlySense\AI-Platform
|
|
129
|
+
...
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Implementation**: Read `.specweave/state/jobs/<jobId>/worker.log` with tail-like behavior, or poll the job state file every second.
|
|
133
|
+
|
|
134
|
+
### View Worker Logs
|
|
135
|
+
|
|
136
|
+
Show detailed worker output:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
/specweave:jobs --logs abc12345
|
|
140
|
+
|
|
141
|
+
π Worker Logs for abc12345 (last 50 lines):
|
|
142
|
+
|
|
143
|
+
[2024-01-15T10:30:00.123Z] Worker started for job abc12345
|
|
144
|
+
[2024-01-15T10:30:00.456Z] Project path: /Users/dev/my-project
|
|
145
|
+
[2024-01-15T10:30:00.789Z] PID: 45678
|
|
146
|
+
[2024-01-15T10:30:01.234Z] Dependencies loaded, starting import...
|
|
147
|
+
[2024-01-15T10:30:02.567Z] Progress: 100/10000 - ado OlySense\Core-Operations
|
|
148
|
+
[2024-01-15T10:30:03.890Z] Progress: 200/10000 - ado OlySense\Core-Operations
|
|
149
|
+
...
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Implementation**: Read `.specweave/state/jobs/<jobId>/worker.log`
|
|
153
|
+
|
|
154
|
+
### Kill Running Job
|
|
155
|
+
|
|
156
|
+
Stop a background job:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
/specweave:jobs --kill abc12345
|
|
160
|
+
|
|
161
|
+
β οΈ Killing job abc12345...
|
|
162
|
+
Type: import-issues
|
|
163
|
+
PID: 45678
|
|
164
|
+
Progress: 2,500/10,000 (25%)
|
|
165
|
+
|
|
166
|
+
β
Job killed. Status changed to 'paused'.
|
|
167
|
+
Resume later: /specweave:jobs --resume abc12345
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Implementation**:
|
|
171
|
+
```typescript
|
|
172
|
+
import { killJob } from '../../../src/core/background/job-launcher.js';
|
|
173
|
+
|
|
174
|
+
const success = killJob(projectPath, jobId);
|
|
175
|
+
if (success) {
|
|
176
|
+
console.log('Job killed successfully');
|
|
177
|
+
}
|
|
90
178
|
```
|
|
91
179
|
|
|
92
180
|
### Resume Paused Job
|
|
93
181
|
|
|
94
|
-
When a job is paused (rate limited, user requested), resume it:
|
|
182
|
+
When a job is paused (rate limited, killed, or user requested), resume it:
|
|
95
183
|
|
|
96
184
|
```
|
|
97
185
|
/specweave:jobs --resume def67890
|
|
@@ -101,8 +189,24 @@ When a job is paused (rate limited, user requested), resume it:
|
|
|
101
189
|
Provider: GitHub
|
|
102
190
|
Resuming from: item 1,234 of 10,000
|
|
103
191
|
|
|
104
|
-
β³
|
|
105
|
-
|
|
192
|
+
β³ Spawning background worker...
|
|
193
|
+
New PID: 45679
|
|
194
|
+
|
|
195
|
+
β
Job resumed in background.
|
|
196
|
+
Check progress: /specweave:jobs --follow def67890
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Implementation**:
|
|
200
|
+
```typescript
|
|
201
|
+
import { launchImportJob } from '../../../src/core/background/job-launcher.js';
|
|
202
|
+
|
|
203
|
+
// Re-launch the worker with existing config
|
|
204
|
+
const result = await launchImportJob({
|
|
205
|
+
type: 'import-issues',
|
|
206
|
+
projectPath,
|
|
207
|
+
coordinatorConfig: existingConfig,
|
|
208
|
+
estimatedTotal: job.progress.total
|
|
209
|
+
});
|
|
106
210
|
```
|
|
107
211
|
|
|
108
212
|
---
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specweave-ado:clone-repos
|
|
3
|
+
description: Clone Azure DevOps repositories to local workspace. Use after init if cloning was skipped, or to add repos later.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Clone Azure DevOps Repositories Command
|
|
7
|
+
|
|
8
|
+
You are an Azure DevOps repository cloning expert. Help users clone repositories from ADO projects to their local workspace.
|
|
9
|
+
|
|
10
|
+
## Purpose
|
|
11
|
+
|
|
12
|
+
This command clones Azure DevOps repositories **after** initial SpecWeave setup (`specweave init`). Use when:
|
|
13
|
+
- User skipped cloning during init
|
|
14
|
+
- Adding repositories from additional projects
|
|
15
|
+
- Re-cloning after cleanup
|
|
16
|
+
- Selective cloning with pattern filtering
|
|
17
|
+
|
|
18
|
+
## Command Syntax
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Interactive mode (prompts for everything)
|
|
22
|
+
/specweave-ado:clone-repos
|
|
23
|
+
|
|
24
|
+
# With pattern filter
|
|
25
|
+
/specweave-ado:clone-repos --pattern "sw-*"
|
|
26
|
+
|
|
27
|
+
# Regex pattern
|
|
28
|
+
/specweave-ado:clone-repos --pattern "regex:^api-.*$"
|
|
29
|
+
|
|
30
|
+
# Specific project only
|
|
31
|
+
/specweave-ado:clone-repos --project "MyProject"
|
|
32
|
+
|
|
33
|
+
# Dry-run (preview only)
|
|
34
|
+
/specweave-ado:clone-repos --dry-run
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Your Task
|
|
38
|
+
|
|
39
|
+
When the user runs this command:
|
|
40
|
+
|
|
41
|
+
### Step 1: Check Prerequisites
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { readEnvFile, parseEnvFile } from '../../../src/utils/env-file.js';
|
|
45
|
+
import chalk from 'chalk';
|
|
46
|
+
|
|
47
|
+
const projectPath = process.cwd();
|
|
48
|
+
const envContent = readEnvFile(projectPath);
|
|
49
|
+
|
|
50
|
+
if (!envContent) {
|
|
51
|
+
console.log(chalk.red('β No .env file found. Run `specweave init` first.'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const parsed = parseEnvFile(envContent);
|
|
56
|
+
|
|
57
|
+
if (!parsed.AZURE_DEVOPS_PAT || !parsed.AZURE_DEVOPS_ORG) {
|
|
58
|
+
console.log(chalk.red('β Missing Azure DevOps credentials.'));
|
|
59
|
+
console.log(chalk.gray(' Run `specweave init` with Azure DevOps provider.'));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const org = parsed.AZURE_DEVOPS_ORG;
|
|
64
|
+
const pat = parsed.AZURE_DEVOPS_PAT;
|
|
65
|
+
|
|
66
|
+
console.log(chalk.blue('\nπ¦ ADO Repository Cloning\n'));
|
|
67
|
+
console.log(chalk.gray(` Organization: ${org}`));
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Step 2: Get Project Selection
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { AzureDevOpsProvider } from '../../../src/core/repo-structure/providers/azure-devops-provider.js';
|
|
74
|
+
|
|
75
|
+
const provider = new AzureDevOpsProvider();
|
|
76
|
+
|
|
77
|
+
// If project specified via CLI, use it
|
|
78
|
+
let selectedProjects: string[] = [];
|
|
79
|
+
|
|
80
|
+
if (args.project) {
|
|
81
|
+
selectedProjects = [args.project];
|
|
82
|
+
console.log(chalk.gray(` Project: ${args.project} (from CLI)`));
|
|
83
|
+
} else {
|
|
84
|
+
// Fetch available projects
|
|
85
|
+
console.log(chalk.gray('\n Fetching projects...'));
|
|
86
|
+
|
|
87
|
+
const response = await fetch(
|
|
88
|
+
`https://dev.azure.com/${org}/_apis/projects?api-version=7.0`,
|
|
89
|
+
{
|
|
90
|
+
headers: {
|
|
91
|
+
'Authorization': `Basic ${Buffer.from(':' + pat).toString('base64')}`,
|
|
92
|
+
'Accept': 'application/json'
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
console.log(chalk.red(`β Failed to fetch projects: ${response.status}`));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const data = await response.json();
|
|
103
|
+
const projects = data.value || [];
|
|
104
|
+
|
|
105
|
+
if (projects.length === 0) {
|
|
106
|
+
console.log(chalk.yellow('β οΈ No projects found in organization.'));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Prompt for project selection
|
|
111
|
+
const { checkbox } = await import('@inquirer/prompts');
|
|
112
|
+
|
|
113
|
+
selectedProjects = await checkbox({
|
|
114
|
+
message: 'Select project(s) to clone repositories from:',
|
|
115
|
+
choices: projects.map(p => ({ name: p.name, value: p.name })),
|
|
116
|
+
required: true
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
console.log(chalk.green(` β ${selectedProjects.length} project(s) selected`));
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Step 3: Fetch Repositories
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const allRepos = [];
|
|
127
|
+
|
|
128
|
+
for (const project of selectedProjects) {
|
|
129
|
+
console.log(chalk.gray(`\n Fetching repos from ${project}...`));
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const repos = await provider.listRepositories(org, project, pat);
|
|
133
|
+
const reposWithProject = repos.map(r => ({ ...r, project }));
|
|
134
|
+
allRepos.push(...reposWithProject);
|
|
135
|
+
console.log(chalk.green(` β Found ${repos.length} repositories`));
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.log(chalk.yellow(` β οΈ Failed: ${error.message}`));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (allRepos.length === 0) {
|
|
142
|
+
console.log(chalk.yellow('\nβ οΈ No repositories found.'));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log(chalk.blue(`\nπ Total: ${allRepos.length} repositories available\n`));
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Step 4: Apply Pattern Filter
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { filterRepositoriesByPattern } from '../../../src/cli/helpers/selection-strategy.js';
|
|
153
|
+
|
|
154
|
+
let filteredRepos = allRepos;
|
|
155
|
+
let patternDescription = 'all';
|
|
156
|
+
|
|
157
|
+
if (args.pattern) {
|
|
158
|
+
// Determine pattern type
|
|
159
|
+
const isRegex = args.pattern.startsWith('regex:');
|
|
160
|
+
const pattern = isRegex ? args.pattern.slice(6) : args.pattern;
|
|
161
|
+
|
|
162
|
+
const clonePattern = {
|
|
163
|
+
strategy: isRegex ? 'pattern-regex' : 'pattern-glob',
|
|
164
|
+
pattern: pattern,
|
|
165
|
+
isRegex
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
filteredRepos = filterRepositoriesByPattern(allRepos, clonePattern);
|
|
169
|
+
patternDescription = `matching "${pattern}"`;
|
|
170
|
+
|
|
171
|
+
console.log(chalk.gray(` Pattern: ${args.pattern}`));
|
|
172
|
+
console.log(chalk.gray(` Matched: ${filteredRepos.length} of ${allRepos.length} repos\n`));
|
|
173
|
+
} else {
|
|
174
|
+
// Prompt for pattern selection
|
|
175
|
+
const { select, input } = await import('@inquirer/prompts');
|
|
176
|
+
|
|
177
|
+
const strategy = await select({
|
|
178
|
+
message: 'How do you want to select repositories?',
|
|
179
|
+
choices: [
|
|
180
|
+
{ name: 'All - Clone all repositories', value: 'all' },
|
|
181
|
+
{ name: 'Pattern (glob) - e.g., "sw-*", "*-backend"', value: 'pattern-glob' },
|
|
182
|
+
{ name: 'Pattern (regex) - e.g., "^api-.*$"', value: 'pattern-regex' }
|
|
183
|
+
]
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if (strategy !== 'all') {
|
|
187
|
+
const pattern = await input({
|
|
188
|
+
message: 'Enter pattern:',
|
|
189
|
+
validate: v => v.trim() ? true : 'Pattern required'
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const clonePattern = {
|
|
193
|
+
strategy,
|
|
194
|
+
pattern: pattern.trim(),
|
|
195
|
+
isRegex: strategy === 'pattern-regex'
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
filteredRepos = filterRepositoriesByPattern(allRepos, clonePattern);
|
|
199
|
+
patternDescription = `matching "${pattern.trim()}"`;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (filteredRepos.length === 0) {
|
|
204
|
+
console.log(chalk.yellow(`β οΈ No repositories ${patternDescription}.`));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Step 5: Preview and Confirm
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
console.log(chalk.blue(`\nπ¦ Repositories to clone (${filteredRepos.length}):\n`));
|
|
213
|
+
|
|
214
|
+
// Show preview (max 20)
|
|
215
|
+
filteredRepos.slice(0, 20).forEach(repo => {
|
|
216
|
+
console.log(chalk.gray(` β’ ${repo.name} (${repo.project})`));
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
if (filteredRepos.length > 20) {
|
|
220
|
+
console.log(chalk.gray(` ... and ${filteredRepos.length - 20} more\n`));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (args.dryRun) {
|
|
224
|
+
console.log(chalk.cyan('\nπ DRY RUN: No repositories will be cloned.\n'));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
229
|
+
|
|
230
|
+
const confirmed = await confirm({
|
|
231
|
+
message: `Clone ${filteredRepos.length} repositories to ./repos/?`,
|
|
232
|
+
default: true
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
if (!confirmed) {
|
|
236
|
+
console.log(chalk.gray('\nβοΈ Cloning cancelled.\n'));
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Step 6: Start Background Cloning
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
import { triggerAdoRepoCloning } from '../../../src/cli/helpers/init/ado-repo-cloning.js';
|
|
245
|
+
|
|
246
|
+
// Build adoProjectSelection
|
|
247
|
+
const adoProjectSelection = {
|
|
248
|
+
org,
|
|
249
|
+
pat,
|
|
250
|
+
projects: selectedProjects
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// Build clonePattern
|
|
254
|
+
const clonePatternResult = args.pattern
|
|
255
|
+
? {
|
|
256
|
+
strategy: args.pattern.startsWith('regex:') ? 'pattern-regex' : 'pattern-glob',
|
|
257
|
+
pattern: args.pattern.startsWith('regex:') ? args.pattern.slice(6) : args.pattern
|
|
258
|
+
}
|
|
259
|
+
: { strategy: 'all' };
|
|
260
|
+
|
|
261
|
+
// Trigger background cloning
|
|
262
|
+
await triggerAdoRepoCloning(projectPath, adoProjectSelection, clonePatternResult);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Examples
|
|
266
|
+
|
|
267
|
+
### Example 1: Interactive Clone
|
|
268
|
+
**User**: `/specweave-ado:clone-repos`
|
|
269
|
+
|
|
270
|
+
**Output**:
|
|
271
|
+
```
|
|
272
|
+
π¦ ADO Repository Cloning
|
|
273
|
+
|
|
274
|
+
Organization: mycompany
|
|
275
|
+
|
|
276
|
+
Fetching projects...
|
|
277
|
+
β 3 projects found
|
|
278
|
+
|
|
279
|
+
Select project(s) to clone repositories from:
|
|
280
|
+
> [x] Platform
|
|
281
|
+
[x] Shared
|
|
282
|
+
[ ] Legacy
|
|
283
|
+
|
|
284
|
+
β 2 project(s) selected
|
|
285
|
+
|
|
286
|
+
Fetching repos from Platform...
|
|
287
|
+
β Found 12 repositories
|
|
288
|
+
Fetching repos from Shared...
|
|
289
|
+
β Found 4 repositories
|
|
290
|
+
|
|
291
|
+
π Total: 16 repositories available
|
|
292
|
+
|
|
293
|
+
How do you want to select repositories?
|
|
294
|
+
> All - Clone all repositories
|
|
295
|
+
|
|
296
|
+
π¦ Repositories to clone (16):
|
|
297
|
+
|
|
298
|
+
β’ sw-frontend (Platform)
|
|
299
|
+
β’ sw-backend (Platform)
|
|
300
|
+
β’ sw-shared-lib (Shared)
|
|
301
|
+
... and 13 more
|
|
302
|
+
|
|
303
|
+
Clone 16 repositories to ./repos/? (Y/n)
|
|
304
|
+
|
|
305
|
+
π¦ Fetching ADO Repositories
|
|
306
|
+
|
|
307
|
+
Fetching from mycompany/Platform...
|
|
308
|
+
β Found 12 repositories in Platform
|
|
309
|
+
Fetching from mycompany/Shared...
|
|
310
|
+
β Found 4 repositories in Shared
|
|
311
|
+
|
|
312
|
+
π Cloning 16 repositories in background...
|
|
313
|
+
|
|
314
|
+
Repositories will be cloned to: ./repos/
|
|
315
|
+
Job ID: abc12345
|
|
316
|
+
|
|
317
|
+
Check progress: /specweave:jobs
|
|
318
|
+
Resume if interrupted: /specweave:jobs --resume abc12345
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Example 2: Pattern Filter
|
|
322
|
+
**User**: `/specweave-ado:clone-repos --pattern "sw-*"`
|
|
323
|
+
|
|
324
|
+
**Output**:
|
|
325
|
+
```
|
|
326
|
+
π¦ ADO Repository Cloning
|
|
327
|
+
|
|
328
|
+
Organization: mycompany
|
|
329
|
+
Pattern: sw-*
|
|
330
|
+
Matched: 8 of 16 repos
|
|
331
|
+
|
|
332
|
+
π¦ Repositories to clone (8):
|
|
333
|
+
|
|
334
|
+
β’ sw-frontend (Platform)
|
|
335
|
+
β’ sw-backend (Platform)
|
|
336
|
+
β’ sw-shared-lib (Shared)
|
|
337
|
+
...
|
|
338
|
+
|
|
339
|
+
Clone 8 repositories to ./repos/? (Y/n)
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Example 3: Dry Run
|
|
343
|
+
**User**: `/specweave-ado:clone-repos --dry-run`
|
|
344
|
+
|
|
345
|
+
**Output**:
|
|
346
|
+
```
|
|
347
|
+
π¦ Repositories to clone (16):
|
|
348
|
+
|
|
349
|
+
β’ sw-frontend (Platform)
|
|
350
|
+
β’ sw-backend (Platform)
|
|
351
|
+
...
|
|
352
|
+
|
|
353
|
+
π DRY RUN: No repositories will be cloned.
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## Important Notes
|
|
357
|
+
|
|
358
|
+
- **Background Cloning**: Repositories clone in background (non-blocking)
|
|
359
|
+
- **Progress Tracking**: Check progress with `/specweave:jobs`
|
|
360
|
+
- **Resumable**: Interrupted clones can resume with `/specweave:jobs --resume <id>`
|
|
361
|
+
- **Auth via PAT**: Uses HTTPS clone URLs with PAT authentication
|
|
362
|
+
- **Target Directory**: Repos are cloned to `./repos/<repo-name>/`
|
|
363
|
+
|
|
364
|
+
## Related Commands
|
|
365
|
+
|
|
366
|
+
- `/specweave:init` - Initial SpecWeave setup (includes repo cloning option)
|
|
367
|
+
- `/specweave:jobs` - Monitor background jobs
|
|
368
|
+
- `/specweave-ado:import-projects` - Import ADO projects with area path mapping
|
|
369
|
+
|
|
370
|
+
## Error Handling
|
|
371
|
+
|
|
372
|
+
- **Missing Credentials**: Prompt to run `specweave init` first
|
|
373
|
+
- **Auth Failures**: Check PAT permissions (vso.code_read scope required)
|
|
374
|
+
- **Clone Failures**: Individual repo failures logged, others continue
|
|
375
|
+
- **Network Errors**: Job pauses, resume with `/specweave:jobs --resume`
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
**Multi-Repo Support**: Perfect for microservices architectures with many ADO repositories.
|