specweave 0.28.61 → 0.28.63
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/CLAUDE.md +23 -0
- package/README.md +23 -1
- package/dist/src/cli/helpers/init/ado-repo-cloning.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/ado-repo-cloning.js +47 -84
- package/dist/src/cli/helpers/init/ado-repo-cloning.js.map +1 -1
- package/dist/src/cli/workers/clone-worker.d.ts +18 -0
- package/dist/src/cli/workers/clone-worker.d.ts.map +1 -0
- package/dist/src/cli/workers/clone-worker.js +191 -0
- package/dist/src/cli/workers/clone-worker.js.map +1 -0
- package/dist/src/core/background/index.d.ts +2 -1
- package/dist/src/core/background/index.d.ts.map +1 -1
- package/dist/src/core/background/index.js +1 -1
- package/dist/src/core/background/index.js.map +1 -1
- package/dist/src/core/background/job-launcher.d.ts +20 -0
- package/dist/src/core/background/job-launcher.d.ts.map +1 -1
- package/dist/src/core/background/job-launcher.js +88 -4
- package/dist/src/core/background/job-launcher.js.map +1 -1
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +11 -0
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +33 -2
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/core/types/increment-metadata.js +32 -5
- package/dist/src/core/types/increment-metadata.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/commands/specweave-done.md +30 -1
- package/plugins/specweave/commands/specweave-jobs.md +7 -7
- package/plugins/specweave/commands/specweave-next.md +66 -14
- package/plugins/specweave/hooks/hooks.json +12 -0
- package/plugins/specweave/hooks/v2/detectors/lifecycle-detector.sh +85 -0
- package/plugins/specweave/hooks/v2/detectors/us-completion-detector.sh +148 -0
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +73 -15
- package/plugins/specweave/hooks/v2/guards/completion-guard.sh +81 -0
- package/plugins/specweave/hooks/v2/handlers/ac-validation-handler.sh +4 -0
- package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +23 -2
- package/plugins/specweave/hooks/v2/handlers/living-docs-handler.sh +24 -3
- package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +193 -0
- package/plugins/specweave/hooks/v2/handlers/status-line-handler.sh +165 -0
- package/plugins/specweave/hooks/v2/handlers/status-update.sh +12 -1
- package/plugins/specweave/hooks/v2/queue/dequeue.sh +4 -0
- package/plugins/specweave/hooks/v2/queue/enqueue.sh +50 -12
- package/plugins/specweave/hooks/v2/queue/processor.sh +141 -12
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +11 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +33 -2
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.js +32 -5
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.js.map +1 -1
package/CLAUDE.md
CHANGED
|
@@ -51,6 +51,29 @@ Edit("tasks.md", "**Status**: [ ] pending", "**Status**: [x] completed");
|
|
|
51
51
|
Edit("spec.md", "- [ ] **AC-US1-01**", "- [x] **AC-US1-01**");
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
### 2b. NEVER Edit metadata.json to "completed" Directly (v0.28.63+)
|
|
55
|
+
|
|
56
|
+
**Direct status change to "completed" = BUG** (auto-completion without user approval)
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
❌ FORBIDDEN (Bug pattern from increment 0081):
|
|
60
|
+
Edit("metadata.json", '"status": "active"', '"status": "completed"')
|
|
61
|
+
→ Status becomes "completed" without ACs checked or user approval!
|
|
62
|
+
|
|
63
|
+
✅ CORRECT workflow:
|
|
64
|
+
1. All tasks completed → auto-transition to "ready_for_review"
|
|
65
|
+
2. /specweave:done <id> → validates ACs + asks for user confirmation
|
|
66
|
+
3. Only then → status becomes "completed" with approvedAt timestamp
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Pre-tool-use hook `completion-guard.sh` BLOCKS direct completion edits.**
|
|
70
|
+
|
|
71
|
+
If you need to implement closure, use:
|
|
72
|
+
```typescript
|
|
73
|
+
MetadataManager.updateStatus(incrementId, IncrementStatus.COMPLETED);
|
|
74
|
+
// Only succeeds if current status is "ready_for_review"
|
|
75
|
+
```
|
|
76
|
+
|
|
54
77
|
### 3. Protected Directories
|
|
55
78
|
|
|
56
79
|
**NEVER delete**: `.specweave/docs/`, `.specweave/increments/`
|
package/README.md
CHANGED
|
@@ -34,9 +34,31 @@ This isn't just a framework we made — it's the framework we use every day. Our
|
|
|
34
34
|
Great tools for simple greenfield projects. But when things get real:
|
|
35
35
|
|
|
36
36
|
- **BMAD** — Constant role-switching (PM → Architect → Dev). Multi-step prompts for every action. Works until you have 5+ services or existing documentation.
|
|
37
|
-
- **SpecKit** —
|
|
37
|
+
- **[SpecKit](https://github.com/github/spec-kit)** — GitHub's excellent open-source toolkit (28k+ stars, Sept 2025). Same 4-phase workflow (Specify → Plan → Tasks → Implement). Clean and minimal — perfect for single-project greenfield MVPs.
|
|
38
38
|
- **Both** — Break down with legacy codebases, multi-repo setups, existing documentation sprawl, and enterprise compliance requirements.
|
|
39
39
|
|
|
40
|
+
### SpecKit → SpecWeave: The Mathematical Relationship
|
|
41
|
+
|
|
42
|
+
**SpecKit is a particular case of SpecWeave** — specifically, it's equivalent to creating ONE SpecWeave increment with no lifecycle management afterward:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
SpecKit output ≡ ONE SpecWeave increment (spec.md + plan.md + tasks.md)
|
|
46
|
+
SpecWeave = N increments + lifecycle + external sync + living docs + hooks
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
In set theory terms: **SpecKit ⊂ SpecWeave** — every SpecKit capability exists in SpecWeave, but SpecWeave adds the enterprise layer:
|
|
50
|
+
|
|
51
|
+
| Capability | SpecKit | SpecWeave |
|
|
52
|
+
|------------|---------|-----------|
|
|
53
|
+
| **Workflow** | Specify → Plan → Tasks → Implement | Same + living docs + hooks + quality gates |
|
|
54
|
+
| **Projects** | Single project | Multi-project, multi-repo, umbrella setups |
|
|
55
|
+
| **External Tools** | None | GitHub Issues, JIRA, Azure DevOps (bidirectional) |
|
|
56
|
+
| **Documentation** | Snapshot (static specs) | Living docs (auto-update after every task) |
|
|
57
|
+
| **Codebase Type** | Greenfield only | Greenfield + Brownfield (10-year legacy? Fine.) |
|
|
58
|
+
| **Team Scale** | Solo/small team | Solo to 50+ teams |
|
|
59
|
+
| **Quality Gates** | None | 3-gate validation (tasks, tests 60%+, docs) |
|
|
60
|
+
| **Plugin Ecosystem** | Minimal | Hooks, skills, agents, multi-AI support |
|
|
61
|
+
|
|
40
62
|
**SpecWeave** — Drop into any codebase. Sync with JIRA/GitHub/ADO. Handle 50 teams or solo MVPs. One workflow.
|
|
41
63
|
|
|
42
64
|
---
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ado-repo-cloning.d.ts","sourceRoot":"","sources":["../../../../../src/cli/helpers/init/ado-repo-cloning.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EAA+B,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"ado-repo-cloning.d.ts","sourceRoot":"","sources":["../../../../../src/cli/helpers/init/ado-repo-cloning.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EAA+B,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGhG;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAoCD;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,mBAAmB,EACxC,YAAY,EAAE,kBAAkB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAuFf"}
|
|
@@ -11,8 +11,28 @@ import path from 'path';
|
|
|
11
11
|
import { existsSync, mkdirSync } from 'fs';
|
|
12
12
|
import { AzureDevOpsProvider } from '../../../core/repo-structure/providers/azure-devops-provider.js';
|
|
13
13
|
import { filterRepositoriesByPattern } from '../selection-strategy.js';
|
|
14
|
-
import {
|
|
15
|
-
|
|
14
|
+
import { launchCloneJob } from '../../../core/background/job-launcher.js';
|
|
15
|
+
/**
|
|
16
|
+
* Build proper ADO clone URL with PAT authentication
|
|
17
|
+
*
|
|
18
|
+
* ADO clone URL format: https://{PAT}@dev.azure.com/{org}/{project}/_git/{repo}
|
|
19
|
+
*
|
|
20
|
+
* The remoteUrl from ADO API may come in different formats:
|
|
21
|
+
* - https://dev.azure.com/org/project/_git/repo
|
|
22
|
+
* - https://org@dev.azure.com/org/project/_git/repo (with org as placeholder)
|
|
23
|
+
*
|
|
24
|
+
* We need to construct a proper URL with PAT authentication.
|
|
25
|
+
* IMPORTANT: URL-encode org, project, and repo names to handle spaces and special characters.
|
|
26
|
+
*/
|
|
27
|
+
function buildAdoCloneUrl(org, project, repoName, pat) {
|
|
28
|
+
// Build clean URL with PAT authentication
|
|
29
|
+
// Format: https://{PAT}@dev.azure.com/{org}/{project}/_git/{repo}
|
|
30
|
+
// URL-encode path segments to handle spaces (e.g., "Nova IoMT Platform")
|
|
31
|
+
const encodedOrg = encodeURIComponent(org);
|
|
32
|
+
const encodedProject = encodeURIComponent(project);
|
|
33
|
+
const encodedRepo = encodeURIComponent(repoName);
|
|
34
|
+
return `https://${pat}@dev.azure.com/${encodedOrg}/${encodedProject}/_git/${encodedRepo}`;
|
|
35
|
+
}
|
|
16
36
|
/**
|
|
17
37
|
* Trigger ADO repository cloning during init
|
|
18
38
|
*
|
|
@@ -37,6 +57,10 @@ export async function triggerAdoRepoCloning(projectPath, adoProjectSelection, cl
|
|
|
37
57
|
console.log(chalk.yellow('\n No ADO projects selected for cloning.\n'));
|
|
38
58
|
return;
|
|
39
59
|
}
|
|
60
|
+
if (!pat) {
|
|
61
|
+
console.log(chalk.yellow('\n No PAT provided. Cannot clone repositories.\n'));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
40
64
|
console.log(chalk.blue('\n📦 Fetching ADO Repositories\n'));
|
|
41
65
|
const provider = new AzureDevOpsProvider();
|
|
42
66
|
const allRepos = [];
|
|
@@ -65,97 +89,36 @@ export async function triggerAdoRepoCloning(projectPath, adoProjectSelection, cl
|
|
|
65
89
|
console.log(chalk.yellow(`\n No repositories${patternDesc} to clone.\n`));
|
|
66
90
|
return;
|
|
67
91
|
}
|
|
68
|
-
console.log(chalk.blue(`\n🔄
|
|
92
|
+
console.log(chalk.blue(`\n🔄 Starting background clone for ${filteredRepos.length} repositories...\n`));
|
|
69
93
|
// Create repos directory if needed
|
|
70
94
|
const reposDir = path.join(projectPath, 'repos');
|
|
71
95
|
if (!existsSync(reposDir)) {
|
|
72
96
|
mkdirSync(reposDir, { recursive: true });
|
|
73
97
|
}
|
|
74
|
-
//
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
projectPath
|
|
84
|
-
|
|
85
|
-
const job = jobManager.createJob('clone-repos', jobConfig, filteredRepos.length);
|
|
86
|
-
jobManager.startJob(job.id);
|
|
87
|
-
// Start cloning asynchronously (non-blocking)
|
|
88
|
-
cloneRepositoriesAsync(projectPath, filteredRepos, org, job.id).catch(error => {
|
|
89
|
-
console.error(chalk.red(`Clone error: ${error instanceof Error ? error.message : String(error)}`));
|
|
90
|
-
jobManager.completeJob(job.id, error instanceof Error ? error.message : String(error));
|
|
98
|
+
// Prepare repositories with clone URLs
|
|
99
|
+
const reposWithUrls = filteredRepos.map(r => ({
|
|
100
|
+
owner: `${org}/${r.project}`,
|
|
101
|
+
name: r.name,
|
|
102
|
+
path: path.join('repos', r.name),
|
|
103
|
+
cloneUrl: buildAdoCloneUrl(org, r.project, r.name, pat)
|
|
104
|
+
}));
|
|
105
|
+
// Launch background clone job (truly async - spawns detached process)
|
|
106
|
+
const result = await launchCloneJob({
|
|
107
|
+
projectPath,
|
|
108
|
+
repositories: reposWithUrls
|
|
91
109
|
});
|
|
92
110
|
// Show progress info
|
|
93
111
|
console.log(chalk.gray(` Repositories will be cloned to: ${reposDir}/`));
|
|
94
|
-
console.log(chalk.gray(` Job ID: ${job.id}`));
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
*
|
|
101
|
-
* This runs in background and updates job progress as repos are cloned.
|
|
102
|
-
*/
|
|
103
|
-
async function cloneRepositoriesAsync(projectPath, repos, org, jobId) {
|
|
104
|
-
const jobManager = getJobManager(projectPath);
|
|
105
|
-
const reposDir = path.join(projectPath, 'repos');
|
|
106
|
-
let completed = 0;
|
|
107
|
-
for (const repo of repos) {
|
|
108
|
-
const repoPath = path.join(reposDir, repo.name);
|
|
109
|
-
// Skip if already exists
|
|
110
|
-
if (existsSync(path.join(repoPath, '.git'))) {
|
|
111
|
-
completed++;
|
|
112
|
-
jobManager.updateProgress(jobId, completed, repo.name, repo.name);
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
try {
|
|
116
|
-
// Clone using HTTPS URL (PAT auth)
|
|
117
|
-
// For ADO: https://dev.azure.com/org/project/_git/repo becomes
|
|
118
|
-
// https://{pat}@dev.azure.com/org/project/_git/repo for auth
|
|
119
|
-
const pat = (await getPatFromJobConfig(projectPath, jobId)) || '';
|
|
120
|
-
const authUrl = repo.remoteUrl.replace('https://', `https://${pat}@`);
|
|
121
|
-
// Create parent directory if needed
|
|
122
|
-
if (!existsSync(reposDir)) {
|
|
123
|
-
mkdirSync(reposDir, { recursive: true });
|
|
124
|
-
}
|
|
125
|
-
// Clone the repository
|
|
126
|
-
const result = execFileNoThrowSync('git', ['clone', authUrl, repo.name], { cwd: reposDir });
|
|
127
|
-
if (result.exitCode === 0) {
|
|
128
|
-
completed++;
|
|
129
|
-
jobManager.updateProgress(jobId, completed, repo.name, repo.name);
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
// Clone failed - mark as failed but continue
|
|
133
|
-
jobManager.updateProgress(jobId, completed, repo.name, undefined, repo.name);
|
|
134
|
-
console.error(chalk.yellow(` Failed to clone ${repo.name}: ${result.stderr || result.stdout}`));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
// Mark repo as failed but continue with others
|
|
139
|
-
jobManager.updateProgress(jobId, completed, repo.name, undefined, repo.name);
|
|
140
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
141
|
-
console.error(chalk.yellow(` Error cloning ${repo.name}: ${errorMsg}`));
|
|
142
|
-
}
|
|
112
|
+
console.log(chalk.gray(` Job ID: ${result.job.id}`));
|
|
113
|
+
if (result.isBackground) {
|
|
114
|
+
console.log(chalk.green(` ✓ Clone job started in background (PID: ${result.pid})`));
|
|
115
|
+
console.log(chalk.cyan('\n Check progress: /specweave:jobs'));
|
|
116
|
+
console.log(chalk.cyan(` Kill if needed: /specweave:jobs --kill ${result.job.id}`));
|
|
117
|
+
console.log(chalk.gray('\n Init will continue - cloning runs independently.\n'));
|
|
143
118
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Get PAT from job config (stored in background-jobs.json)
|
|
149
|
-
*/
|
|
150
|
-
async function getPatFromJobConfig(projectPath, jobId) {
|
|
151
|
-
// PAT is stored in .env, not in job config (security)
|
|
152
|
-
// Read from environment or .env file
|
|
153
|
-
const { readEnvFile, parseEnvFile } = await import('../../../utils/env-file.js');
|
|
154
|
-
const envContent = readEnvFile(projectPath);
|
|
155
|
-
if (envContent) {
|
|
156
|
-
const parsed = parseEnvFile(envContent);
|
|
157
|
-
return parsed.AZURE_DEVOPS_PAT || null;
|
|
119
|
+
else {
|
|
120
|
+
console.log(chalk.yellow(' ⚠️ Running in foreground (clone worker not found)'));
|
|
121
|
+
console.log(chalk.gray(' Init will block until cloning completes.\n'));
|
|
158
122
|
}
|
|
159
|
-
return process.env.AZURE_DEVOPS_PAT || null;
|
|
160
123
|
}
|
|
161
124
|
//# sourceMappingURL=ado-repo-cloning.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ado-repo-cloning.js","sourceRoot":"","sources":["../../../../../src/cli/helpers/init/ado-repo-cloning.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iEAAiE,CAAC;AACtG,OAAO,EAAE,2BAA2B,EAA2B,MAAM,0BAA0B,CAAC;AAChG,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ado-repo-cloning.js","sourceRoot":"","sources":["../../../../../src/cli/helpers/init/ado-repo-cloning.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Background Clone Worker
|
|
4
|
+
*
|
|
5
|
+
* Standalone script that runs repository cloning in a detached process.
|
|
6
|
+
* Survives terminal close - progress tracked via job state file.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node clone-worker.js <jobId> <projectPath>
|
|
10
|
+
*
|
|
11
|
+
* The worker reads job configuration from:
|
|
12
|
+
* .specweave/state/jobs/<jobId>/config.json
|
|
13
|
+
*
|
|
14
|
+
* And updates progress to:
|
|
15
|
+
* .specweave/state/background-jobs.json
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=clone-worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone-worker.d.ts","sourceRoot":"","sources":["../../../../src/cli/workers/clone-worker.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Background Clone Worker
|
|
4
|
+
*
|
|
5
|
+
* Standalone script that runs repository cloning in a detached process.
|
|
6
|
+
* Survives terminal close - progress tracked via job state file.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node clone-worker.js <jobId> <projectPath>
|
|
10
|
+
*
|
|
11
|
+
* The worker reads job configuration from:
|
|
12
|
+
* .specweave/state/jobs/<jobId>/config.json
|
|
13
|
+
*
|
|
14
|
+
* And updates progress to:
|
|
15
|
+
* .specweave/state/background-jobs.json
|
|
16
|
+
*/
|
|
17
|
+
import * as fs from 'fs';
|
|
18
|
+
import * as path from 'path';
|
|
19
|
+
import { fileURLToPath } from 'url';
|
|
20
|
+
import { spawn } from 'child_process';
|
|
21
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
+
const __dirname = path.dirname(__filename);
|
|
23
|
+
/**
|
|
24
|
+
* Clone a single repository using async spawn
|
|
25
|
+
*/
|
|
26
|
+
async function cloneRepository(cloneUrl, targetDir, repoName, log) {
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
log(`Starting clone: ${repoName}`);
|
|
29
|
+
// Ensure parent directory exists
|
|
30
|
+
const parentDir = path.dirname(targetDir);
|
|
31
|
+
if (!fs.existsSync(parentDir)) {
|
|
32
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
// Spawn git clone process
|
|
35
|
+
const gitProcess = spawn('git', ['clone', cloneUrl, repoName], {
|
|
36
|
+
cwd: parentDir,
|
|
37
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
38
|
+
});
|
|
39
|
+
let stderr = '';
|
|
40
|
+
gitProcess.stderr.on('data', (data) => {
|
|
41
|
+
stderr += data.toString();
|
|
42
|
+
});
|
|
43
|
+
gitProcess.on('close', (code) => {
|
|
44
|
+
if (code === 0) {
|
|
45
|
+
log(`Successfully cloned: ${repoName}`);
|
|
46
|
+
resolve({ success: true });
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Sanitize error message (remove PAT from URL)
|
|
50
|
+
const sanitizedError = stderr.replace(/https:\/\/[^@]+@/g, 'https://***@');
|
|
51
|
+
log(`Failed to clone ${repoName}: ${sanitizedError}`);
|
|
52
|
+
resolve({ success: false, error: sanitizedError });
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
gitProcess.on('error', (error) => {
|
|
56
|
+
log(`Error spawning git for ${repoName}: ${error.message}`);
|
|
57
|
+
resolve({ success: false, error: error.message });
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Main worker entry point
|
|
63
|
+
*/
|
|
64
|
+
async function main() {
|
|
65
|
+
const args = process.argv.slice(2);
|
|
66
|
+
if (args.length < 2) {
|
|
67
|
+
console.error('Usage: clone-worker.js <jobId> <projectPath>');
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
const jobId = args[0];
|
|
71
|
+
const projectPath = args[1];
|
|
72
|
+
// Write PID file for process management
|
|
73
|
+
const pidFile = path.join(projectPath, '.specweave', 'state', 'jobs', jobId, 'worker.pid');
|
|
74
|
+
fs.mkdirSync(path.dirname(pidFile), { recursive: true });
|
|
75
|
+
fs.writeFileSync(pidFile, process.pid.toString());
|
|
76
|
+
// Setup cleanup on exit
|
|
77
|
+
const cleanup = () => {
|
|
78
|
+
try {
|
|
79
|
+
if (fs.existsSync(pidFile)) {
|
|
80
|
+
fs.unlinkSync(pidFile);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Ignore cleanup errors
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
process.on('exit', cleanup);
|
|
88
|
+
process.on('SIGTERM', () => {
|
|
89
|
+
cleanup();
|
|
90
|
+
process.exit(0);
|
|
91
|
+
});
|
|
92
|
+
process.on('SIGINT', () => {
|
|
93
|
+
cleanup();
|
|
94
|
+
process.exit(0);
|
|
95
|
+
});
|
|
96
|
+
// Dynamically import job manager
|
|
97
|
+
let getJobManager;
|
|
98
|
+
try {
|
|
99
|
+
// Load job configuration
|
|
100
|
+
const configPath = path.join(projectPath, '.specweave', 'state', 'jobs', jobId, 'config.json');
|
|
101
|
+
if (!fs.existsSync(configPath)) {
|
|
102
|
+
throw new Error(`Job config not found: ${configPath}`);
|
|
103
|
+
}
|
|
104
|
+
const jobConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
105
|
+
// Log to worker-specific log file
|
|
106
|
+
const logPath = path.join(projectPath, '.specweave', 'state', 'jobs', jobId, 'worker.log');
|
|
107
|
+
const log = (msg) => {
|
|
108
|
+
const timestamp = new Date().toISOString();
|
|
109
|
+
const logLine = `[${timestamp}] ${msg}\n`;
|
|
110
|
+
fs.appendFileSync(logPath, logLine);
|
|
111
|
+
// Also output to stdout for debugging
|
|
112
|
+
process.stdout.write(logLine);
|
|
113
|
+
};
|
|
114
|
+
log(`Clone worker started for job ${jobId}`);
|
|
115
|
+
log(`Project path: ${projectPath}`);
|
|
116
|
+
log(`PID: ${process.pid}`);
|
|
117
|
+
log(`Repositories to clone: ${jobConfig.repositories.length}`);
|
|
118
|
+
// Dynamically import job manager
|
|
119
|
+
const jobManagerModule = await import('../../core/background/job-manager.js');
|
|
120
|
+
getJobManager = jobManagerModule.getJobManager;
|
|
121
|
+
// Get job manager and mark as running
|
|
122
|
+
const jobManager = getJobManager(projectPath);
|
|
123
|
+
jobManager.startJob(jobId);
|
|
124
|
+
log('Job manager loaded, starting clone operations...');
|
|
125
|
+
// Clone repositories sequentially to avoid overwhelming the system
|
|
126
|
+
const repos = jobConfig.repositories;
|
|
127
|
+
let completed = 0;
|
|
128
|
+
let succeeded = 0;
|
|
129
|
+
let failed = 0;
|
|
130
|
+
for (const repo of repos) {
|
|
131
|
+
const repoPath = path.join(projectPath, repo.path);
|
|
132
|
+
// Skip if already exists
|
|
133
|
+
if (fs.existsSync(path.join(repoPath, '.git'))) {
|
|
134
|
+
log(`Skipping ${repo.name} (already exists)`);
|
|
135
|
+
completed++;
|
|
136
|
+
succeeded++;
|
|
137
|
+
jobManager.updateProgress(jobId, completed, repo.name, repo.name);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
// Clone the repository
|
|
141
|
+
const result = await cloneRepository(repo.cloneUrl, repoPath, repo.name, log);
|
|
142
|
+
completed++;
|
|
143
|
+
if (result.success) {
|
|
144
|
+
succeeded++;
|
|
145
|
+
jobManager.updateProgress(jobId, completed, repo.name, repo.name);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
failed++;
|
|
149
|
+
jobManager.updateProgress(jobId, completed, repo.name, undefined, repo.name);
|
|
150
|
+
}
|
|
151
|
+
// Small delay between clones to be nice to the server
|
|
152
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
153
|
+
}
|
|
154
|
+
// Mark job as complete
|
|
155
|
+
const errorMsg = failed > 0 ? `${failed} repositories failed to clone` : undefined;
|
|
156
|
+
jobManager.completeJob(jobId, errorMsg);
|
|
157
|
+
// Write result summary
|
|
158
|
+
const resultPath = path.join(projectPath, '.specweave', 'state', 'jobs', jobId, 'result.json');
|
|
159
|
+
fs.writeFileSync(resultPath, JSON.stringify({
|
|
160
|
+
totalCount: repos.length,
|
|
161
|
+
succeeded,
|
|
162
|
+
failed,
|
|
163
|
+
completedAt: new Date().toISOString()
|
|
164
|
+
}, null, 2));
|
|
165
|
+
log(`Clone job completed: ${succeeded}/${repos.length} succeeded, ${failed} failed`);
|
|
166
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
// Log error
|
|
170
|
+
const logPath = path.join(projectPath, '.specweave', 'state', 'jobs', jobId, 'worker.log');
|
|
171
|
+
fs.appendFileSync(logPath, `[${new Date().toISOString()}] ERROR: ${error.message}\n`);
|
|
172
|
+
fs.appendFileSync(logPath, `${error.stack}\n`);
|
|
173
|
+
// Mark job as failed
|
|
174
|
+
try {
|
|
175
|
+
const jobManagerModule = await import('../../core/background/job-manager.js');
|
|
176
|
+
const jobManager = jobManagerModule.getJobManager(projectPath);
|
|
177
|
+
jobManager.completeJob(jobId, error.message);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// Ignore if can't update job
|
|
181
|
+
}
|
|
182
|
+
console.error(`Worker error: ${error.message}`);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Run worker
|
|
187
|
+
main().catch((error) => {
|
|
188
|
+
console.error('Fatal worker error:', error);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
});
|
|
191
|
+
//# sourceMappingURL=clone-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone-worker.js","sourceRoot":"","sources":["../../../../src/cli/workers/clone-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,5 +15,6 @@
|
|
|
15
15
|
*/
|
|
16
16
|
export * from './types.js';
|
|
17
17
|
export * from './job-manager.js';
|
|
18
|
-
export
|
|
18
|
+
export { launchImportJob, launchCloneJob, isJobRunning, killJob, getJobLog, getJobResult, cleanupOldJobs } from './job-launcher.js';
|
|
19
|
+
export type { LaunchOptions, LaunchResult, CloneLaunchOptions } from './job-launcher.js';
|
|
19
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/background/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/background/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpI,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
*/
|
|
16
16
|
export * from './types.js';
|
|
17
17
|
export * from './job-manager.js';
|
|
18
|
-
export
|
|
18
|
+
export { launchImportJob, launchCloneJob, isJobRunning, killJob, getJobLog, getJobResult, cleanupOldJobs } from './job-launcher.js';
|
|
19
19
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/background/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/background/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -31,6 +31,26 @@ export interface LaunchResult {
|
|
|
31
31
|
* @returns Job info and process details
|
|
32
32
|
*/
|
|
33
33
|
export declare function launchImportJob(options: LaunchOptions): Promise<LaunchResult>;
|
|
34
|
+
export interface CloneLaunchOptions {
|
|
35
|
+
/** Project path */
|
|
36
|
+
projectPath: string;
|
|
37
|
+
/** Repositories to clone with URLs */
|
|
38
|
+
repositories: Array<{
|
|
39
|
+
owner: string;
|
|
40
|
+
name: string;
|
|
41
|
+
path: string;
|
|
42
|
+
cloneUrl: string;
|
|
43
|
+
}>;
|
|
44
|
+
/** Run in foreground (blocking) instead of background */
|
|
45
|
+
foreground?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Launch a clone job
|
|
49
|
+
*
|
|
50
|
+
* @param options Launch configuration
|
|
51
|
+
* @returns Job info and process details
|
|
52
|
+
*/
|
|
53
|
+
export declare function launchCloneJob(options: CloneLaunchOptions): Promise<LaunchResult>;
|
|
34
54
|
/**
|
|
35
55
|
* Check if a background job is still running
|
|
36
56
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-launcher.d.ts","sourceRoot":"","sources":["../../../../src/core/background/job-launcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"job-launcher.d.ts","sourceRoot":"","sources":["../../../../src/core/background/job-launcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAmC,MAAM,YAAY,CAAC;AAE1F,MAAM,WAAW,aAAa;IAC5B,eAAe;IACf,IAAI,EAAE,OAAO,CAAC;IACd,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,iBAAiB,EAAE,GAAG,CAAC;IACvB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,aAAa,CAAC;IACnB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAiFnF;AAED,MAAM,WAAW,kBAAkB;IACjC,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,YAAY,EAAE,KAAK,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CA6EvF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAiBxE;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAqBnE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAexF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI,CAY3E;AAwCD;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAU,GAAG,IAAI,CA8B9E"}
|