specweave 0.21.3 → 0.22.0
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 +198 -6
- package/README.md +33 -3
- package/dist/plugins/specweave-github/lib/CodeValidator.d.ts +101 -0
- package/dist/plugins/specweave-github/lib/CodeValidator.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/CodeValidator.js +219 -0
- package/dist/plugins/specweave-github/lib/CodeValidator.js.map +1 -0
- package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.d.ts +182 -0
- package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.js +603 -0
- package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.js.map +1 -0
- package/dist/plugins/specweave-github/lib/types.d.ts +34 -0
- package/dist/plugins/specweave-github/lib/types.d.ts.map +1 -1
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +60 -5
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/config/types.d.ts +8 -8
- package/dist/src/core/living-docs/CompletionPropagator.d.ts.map +1 -1
- package/dist/src/core/living-docs/CompletionPropagator.js +4 -3
- package/dist/src/core/living-docs/CompletionPropagator.js.map +1 -1
- package/dist/src/core/living-docs/SpecDistributor.d.ts +5 -0
- package/dist/src/core/living-docs/SpecDistributor.d.ts.map +1 -1
- package/dist/src/core/living-docs/SpecDistributor.js +12 -0
- package/dist/src/core/living-docs/SpecDistributor.js.map +1 -1
- package/dist/src/core/living-docs/project-detector.d.ts.map +1 -1
- package/dist/src/core/living-docs/project-detector.js +38 -0
- package/dist/src/core/living-docs/project-detector.js.map +1 -1
- package/dist/src/core/types/config.d.ts +23 -0
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js +10 -0
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/init/ArchitecturePresenter.d.ts +47 -0
- package/dist/src/init/ArchitecturePresenter.d.ts.map +1 -0
- package/dist/src/init/ArchitecturePresenter.js +180 -0
- package/dist/src/init/ArchitecturePresenter.js.map +1 -0
- package/dist/src/init/InitFlow.d.ts.map +1 -1
- package/dist/src/init/InitFlow.js +30 -1
- package/dist/src/init/InitFlow.js.map +1 -1
- package/dist/src/init/architecture/CostEstimator.d.ts +52 -0
- package/dist/src/init/architecture/CostEstimator.d.ts.map +1 -0
- package/dist/src/init/architecture/CostEstimator.js +107 -0
- package/dist/src/init/architecture/CostEstimator.js.map +1 -0
- package/dist/src/init/architecture/InfrastructureMapper.d.ts +41 -0
- package/dist/src/init/architecture/InfrastructureMapper.d.ts.map +1 -0
- package/dist/src/init/architecture/InfrastructureMapper.js +140 -0
- package/dist/src/init/architecture/InfrastructureMapper.js.map +1 -0
- package/dist/src/init/architecture/ProjectGenerator.d.ts +44 -0
- package/dist/src/init/architecture/ProjectGenerator.d.ts.map +1 -0
- package/dist/src/init/architecture/ProjectGenerator.js +216 -0
- package/dist/src/init/architecture/ProjectGenerator.js.map +1 -0
- package/dist/src/init/research/src/config/types.d.ts +8 -8
- package/package.json +9 -8
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-github/lib/CodeValidator.js +195 -0
- package/plugins/specweave-github/lib/CodeValidator.ts +284 -0
- package/plugins/specweave-github/lib/ThreeLayerSyncManager.js +545 -0
- package/plugins/specweave-github/lib/ThreeLayerSyncManager.ts +809 -0
- package/plugins/specweave-github/lib/types.ts +38 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1200 -0
- package/src/templates/AGENTS.md.template +22 -1
package/CLAUDE.md
CHANGED
|
@@ -24,21 +24,23 @@ Users receive a different CLAUDE.md via the template system.
|
|
|
24
24
|
/SESSION-SUMMARY-2025-10-28.md # NO! Goes to increment reports/
|
|
25
25
|
/ADR-006-DEEP-ANALYSIS.md # NO! Goes to .specweave/docs/internal/architecture/adr/
|
|
26
26
|
/ANALYSIS-MULTI-TOOL-COMPARISON.md # NO! Goes to increment reports/
|
|
27
|
+
/QUICK-START.md # NO! Goes to increment reports/
|
|
27
28
|
/migration-helper.sh # NO! Goes to increment scripts/
|
|
28
29
|
/execution.log # NO! Goes to increment logs/
|
|
29
30
|
|
|
30
31
|
✅ CORRECT - INCREMENT FOLDERS:
|
|
31
32
|
.specweave/increments/0004-plugin-architecture/
|
|
32
|
-
├── spec.md #
|
|
33
|
+
├── spec.md # ⚠️ ONLY THESE 3 FILES in root!
|
|
33
34
|
├── plan.md
|
|
34
35
|
├── tasks.md # Tasks with embedded tests
|
|
35
|
-
├── reports/ # ✅
|
|
36
|
+
├── reports/ # ✅ ALL REPORTS HERE!
|
|
36
37
|
│ ├── PLUGIN-MIGRATION-COMPLETE.md # ✅ Completion reports
|
|
37
38
|
│ ├── SESSION-SUMMARY.md # ✅ Session summaries
|
|
39
|
+
│ ├── QUICK-START.md # ✅ Quick start guides
|
|
38
40
|
│ └── ANALYSIS-*.md # ✅ Analysis files
|
|
39
|
-
├── scripts/ # ✅
|
|
41
|
+
├── scripts/ # ✅ ALL SCRIPTS HERE!
|
|
40
42
|
│ └── migration-helper.sh # ✅ Helper scripts
|
|
41
|
-
└── logs/ # ✅
|
|
43
|
+
└── logs/ # ✅ ALL LOGS HERE!
|
|
42
44
|
└── execution.log # ✅ Execution logs
|
|
43
45
|
|
|
44
46
|
.specweave/docs/internal/architecture/ # ✅ PUT ADRS/DIAGRAMS HERE!
|
|
@@ -48,6 +50,105 @@ Users receive a different CLAUDE.md via the template system.
|
|
|
48
50
|
|
|
49
51
|
**Before committing, ALWAYS check**: `git status` - If you see `.md` files in root, MOVE THEM!
|
|
50
52
|
|
|
53
|
+
### 📁 Increment Structure Rules (MANDATORY)
|
|
54
|
+
|
|
55
|
+
**ONLY 3 files allowed in increment root**:
|
|
56
|
+
1. ✅ `spec.md` - Specification
|
|
57
|
+
2. ✅ `plan.md` - Implementation plan
|
|
58
|
+
3. ✅ `tasks.md` - Tasks with embedded tests
|
|
59
|
+
|
|
60
|
+
**Everything else MUST be in subfolders**:
|
|
61
|
+
- `reports/` - Session summaries, completion reports, analysis files, quick-start guides
|
|
62
|
+
- `scripts/` - Helper scripts, migrations, utilities
|
|
63
|
+
- `logs/` - Execution logs, debug output, temp files
|
|
64
|
+
|
|
65
|
+
**Examples of files that belong in subfolders**:
|
|
66
|
+
- `QUICK-START.md` → `reports/QUICK-START.md`
|
|
67
|
+
- `SESSION-NOTES.md` → `reports/SESSION-NOTES.md`
|
|
68
|
+
- `ULTRATHINK-*.md` → `reports/ULTRATHINK-*.md`
|
|
69
|
+
- `validation.sh` → `scripts/validation.sh`
|
|
70
|
+
- `debug.log` → `logs/debug.log`
|
|
71
|
+
|
|
72
|
+
**Why this matters**:
|
|
73
|
+
- ✅ Clean, predictable structure
|
|
74
|
+
- ✅ Easy to find files by type
|
|
75
|
+
- ✅ No increment root clutter
|
|
76
|
+
- ✅ Consistent across all increments
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 🛡️ CRITICAL: NEVER DELETE .specweave/ DIRECTORIES!
|
|
81
|
+
|
|
82
|
+
**⛔ MASS DELETION PROTECTION IS ACTIVE ⛔**
|
|
83
|
+
|
|
84
|
+
**PROTECTED DIRECTORIES**:
|
|
85
|
+
- `.specweave/docs/` - All project documentation (internal + public)
|
|
86
|
+
- `.specweave/increments/` - All increment history and specifications
|
|
87
|
+
|
|
88
|
+
**WHAT THIS MEANS**:
|
|
89
|
+
- ❌ **NEVER** run `rm -rf .specweave/docs` or `rm -rf .specweave/increments`
|
|
90
|
+
- ❌ **NEVER** delete more than 50 files in these directories at once
|
|
91
|
+
- ✅ Pre-commit hook will **BLOCK** accidental mass deletions
|
|
92
|
+
- ✅ If intentional, bypass with `git commit --no-verify`
|
|
93
|
+
|
|
94
|
+
**WHY THIS EXISTS**:
|
|
95
|
+
On 2025-11-17, an accidental mass deletion occurred (1,200+ files). All files were recovered via `git restore`, but this protection prevents future incidents.
|
|
96
|
+
|
|
97
|
+
**IF YOU ACCIDENTALLY DELETE**:
|
|
98
|
+
```bash
|
|
99
|
+
# Immediately restore:
|
|
100
|
+
git restore .specweave/
|
|
101
|
+
|
|
102
|
+
# Verify restoration:
|
|
103
|
+
git status
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**See**: `.specweave/increments/0039/reports/ACCIDENTAL-DELETION-RECOVERY-2025-11-17.md`
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## ⚠️ CRITICAL: NEVER USE `specweave init . --force` FOR REINSTALLS!
|
|
111
|
+
|
|
112
|
+
**⛔ COMMON MISTAKE THAT DELETES ALL DATA ⛔**
|
|
113
|
+
|
|
114
|
+
**THE DANGER**:
|
|
115
|
+
```bash
|
|
116
|
+
# ❌ DANGEROUS (deletes ALL increments and docs):
|
|
117
|
+
specweave init . --force
|
|
118
|
+
|
|
119
|
+
# What --force actually does:
|
|
120
|
+
# 1. Skips all confirmation prompts
|
|
121
|
+
# 2. AUTOMATICALLY DELETES .specweave/ entirely
|
|
122
|
+
# 3. Loses all increments, docs, and history
|
|
123
|
+
# 4. No backup unless you create one manually
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**SAFE ALTERNATIVES**:
|
|
127
|
+
```bash
|
|
128
|
+
# ✅ SAFE - Update files, keep all data:
|
|
129
|
+
specweave init .
|
|
130
|
+
# When prompted, select: "Continue working"
|
|
131
|
+
|
|
132
|
+
# ✅ SAFE - Always interactive, never deletes:
|
|
133
|
+
npx specweave init .
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**WHY THIS MATTERS**:
|
|
137
|
+
- Documentation used to recommend `--force` for troubleshooting (FIXED in v0.21.4+)
|
|
138
|
+
- Users followed the docs and lost all their work
|
|
139
|
+
- Now `--force` has multiple safeguards:
|
|
140
|
+
- ⚠️ BIG RED WARNING before deletion
|
|
141
|
+
- ✅ ALWAYS requires confirmation (even in force mode)
|
|
142
|
+
- 📦 Automatic backup created before deletion
|
|
143
|
+
- 🔒 Pre-commit hook blocks accidental commits
|
|
144
|
+
|
|
145
|
+
**IF YOU NEED A FRESH START**:
|
|
146
|
+
1. Backup first: `cp -r .specweave .specweave.backup-$(date +%Y%m%d)`
|
|
147
|
+
2. Run: `specweave init .` (select "Fresh start" option)
|
|
148
|
+
3. Or: `specweave init . --force` (requires confirmation + creates auto-backup)
|
|
149
|
+
|
|
150
|
+
**NEVER use `--force` unless you want to DELETE EVERYTHING!**
|
|
151
|
+
|
|
51
152
|
---
|
|
52
153
|
|
|
53
154
|
## Tool Support
|
|
@@ -353,12 +454,103 @@ npm run build # Compile TypeScript
|
|
|
353
454
|
|
|
354
455
|
### Testing
|
|
355
456
|
|
|
457
|
+
**Test Framework**: **Vitest** (migrated from Jest on 2025-11-17)
|
|
458
|
+
|
|
356
459
|
```bash
|
|
357
|
-
npm test #
|
|
358
|
-
npm run test:
|
|
460
|
+
npm test # Smoke tests (quick validation)
|
|
461
|
+
npm run test:unit # Unit tests with Vitest
|
|
462
|
+
npm run test:integration # Integration tests with Vitest
|
|
359
463
|
npm run test:e2e # E2E tests (Playwright)
|
|
464
|
+
npm run test:all # All tests
|
|
465
|
+
npm run test:coverage # Coverage report
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Why Vitest?**
|
|
469
|
+
- ✅ ESM-native (no tsconfig hacks)
|
|
470
|
+
- ✅ Faster than Jest
|
|
471
|
+
- ✅ Better TypeScript integration
|
|
472
|
+
- ✅ Native import.meta.url support
|
|
473
|
+
- ✅ Modern, actively maintained
|
|
474
|
+
|
|
475
|
+
**Test Organization** (4 categories):
|
|
476
|
+
- `tests/unit/` - Pure logic tests (no I/O) - **Vitest**
|
|
477
|
+
- `tests/plugin-validation/` - Plugin structure contracts
|
|
478
|
+
- `tests/integration/` - 4 semantic categories - **Vitest**:
|
|
479
|
+
- `external-tools/` - GitHub, JIRA, ADO, Kafka sync
|
|
480
|
+
- `core/` - Core framework + workflows
|
|
481
|
+
- `generators/` - Code generation (frontend, backend, ML)
|
|
482
|
+
- `features/` - Feature plugins (Figma, i18n, diagrams, etc.)
|
|
483
|
+
- `tests/e2e/` - Full user scenarios - **Playwright**
|
|
484
|
+
|
|
485
|
+
**Writing Tests**:
|
|
486
|
+
```typescript
|
|
487
|
+
// Import from vitest (NOT jest)
|
|
488
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
489
|
+
|
|
490
|
+
// Mocking
|
|
491
|
+
vi.mock('fs/promises');
|
|
492
|
+
const mockFn = vi.fn();
|
|
493
|
+
vi.clearAllMocks();
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**Details**: `.specweave/docs/internal/architecture/TEST-ORGANIZATION-PROPOSAL.md`
|
|
497
|
+
|
|
498
|
+
### Test Isolation (CRITICAL - Prevents .specweave/ Deletion!)
|
|
499
|
+
|
|
500
|
+
**🚨 MANDATORY FOR ALL TESTS creating .specweave/ structures:**
|
|
501
|
+
|
|
502
|
+
**THE PROBLEM**: Tests using `process.cwd()` can accidentally delete the project `.specweave/` folder containing all your work!
|
|
503
|
+
|
|
504
|
+
**CORRECT PATTERN** (ALWAYS use this):
|
|
505
|
+
```typescript
|
|
506
|
+
import * as os from 'os';
|
|
507
|
+
import * as path from 'path';
|
|
508
|
+
|
|
509
|
+
// ✅ SAFE: Uses isolated temp directory
|
|
510
|
+
const testRoot = path.join(os.tmpdir(), 'test-name-' + Date.now());
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
**DANGEROUS PATTERN** (NEVER use this):
|
|
514
|
+
```typescript
|
|
515
|
+
// ❌ DANGER: Creates directories in project root!
|
|
516
|
+
const testRoot = path.join(process.cwd(), '.test-something');
|
|
517
|
+
const testPath = path.join(__dirname, '..', '.specweave', 'increments');
|
|
360
518
|
```
|
|
361
519
|
|
|
520
|
+
**Why This Matters**:
|
|
521
|
+
1. Tests create mock `.specweave/` structures for testing
|
|
522
|
+
2. Cleanup uses `fs.rm(testRoot, { recursive: true })`
|
|
523
|
+
3. If `testRoot` points to project root → **DELETES REAL .specweave/!**
|
|
524
|
+
4. You lose all increments, docs, and history
|
|
525
|
+
|
|
526
|
+
**Use Test Utilities** (RECOMMENDED):
|
|
527
|
+
```typescript
|
|
528
|
+
import { createIsolatedTestDir, createSpecweaveStructure } from '../test-utils/isolated-test-dir';
|
|
529
|
+
|
|
530
|
+
test('my test', async () => {
|
|
531
|
+
const { testDir, cleanup } = await createIsolatedTestDir('my-test');
|
|
532
|
+
|
|
533
|
+
try {
|
|
534
|
+
// Setup .specweave structure in isolated directory
|
|
535
|
+
await createSpecweaveStructure(testDir);
|
|
536
|
+
|
|
537
|
+
// Test code here - NEVER touches project .specweave/
|
|
538
|
+
const incrementPath = path.join(testDir, '.specweave', 'increments', '0001-test');
|
|
539
|
+
// ...
|
|
540
|
+
} finally {
|
|
541
|
+
await cleanup(); // ALWAYS cleanup
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
**Protection Layers**:
|
|
547
|
+
1. ✅ **Pre-commit hook**: Blocks commits with dangerous test patterns
|
|
548
|
+
2. ✅ **Test utilities**: `tests/test-utils/isolated-test-dir.ts`
|
|
549
|
+
3. ✅ **Documentation**: This section
|
|
550
|
+
|
|
551
|
+
**Related Incident**: 2025-11-17 - Multiple `.specweave/` deletions traced to dangerous test patterns
|
|
552
|
+
**Root Cause Analysis**: `.specweave/increments/0037/reports/DELETION-ROOT-CAUSE-2025-11-17.md`
|
|
553
|
+
|
|
362
554
|
### Build Health Checks
|
|
363
555
|
|
|
364
556
|
**CRITICAL**: TypeScript ES Modules require specific practices:
|
package/README.md
CHANGED
|
@@ -232,8 +232,18 @@ Claude implements Task 1:
|
|
|
232
232
|
# Install SpecWeave
|
|
233
233
|
npm install -g specweave
|
|
234
234
|
|
|
235
|
-
# Initialize
|
|
235
|
+
# Initialize with Strategic Init (AI-powered research)
|
|
236
236
|
specweave init my-project
|
|
237
|
+
|
|
238
|
+
# Strategic Init guides you through 6 phases:
|
|
239
|
+
# Phase 1: Vision & Market Research
|
|
240
|
+
# Phase 2: Scaling & Performance Goals
|
|
241
|
+
# Phase 3: Data & Compliance Detection
|
|
242
|
+
# Phase 4: Budget & Cloud Credits
|
|
243
|
+
# Phase 5: Methodology & Organization
|
|
244
|
+
# Phase 6: Repository Selection (optional)
|
|
245
|
+
|
|
246
|
+
# Result: Architecture recommendation, team plan, cost estimates
|
|
237
247
|
cd my-project
|
|
238
248
|
|
|
239
249
|
# Start building
|
|
@@ -242,6 +252,15 @@ cd my-project
|
|
|
242
252
|
/specweave:done 0001 # Complete increment
|
|
243
253
|
```
|
|
244
254
|
|
|
255
|
+
### Multi-Project Setup
|
|
256
|
+
```bash
|
|
257
|
+
# Initialize with multiple projects
|
|
258
|
+
specweave init --projects backend,frontend,mobile
|
|
259
|
+
|
|
260
|
+
# Tasks automatically split by project keyword detection
|
|
261
|
+
# Each project gets its own user stories and GitHub issues
|
|
262
|
+
```
|
|
263
|
+
|
|
245
264
|
### Brownfield (Existing Project)
|
|
246
265
|
```bash
|
|
247
266
|
# Initialize SpecWeave in existing project
|
|
@@ -255,7 +274,7 @@ specweave init .
|
|
|
255
274
|
/specweave:increment "Add dark mode"
|
|
256
275
|
```
|
|
257
276
|
|
|
258
|
-
**[→ Complete Quickstart Guide](https://spec-weave.com/docs/guides/getting-started/quickstart)**
|
|
277
|
+
**[→ Complete Quickstart Guide](https://spec-weave.com/docs/guides/getting-started/quickstart)** | **[→ Strategic Init Guide](https://spec-weave.com/docs/guides/strategic-init)**
|
|
259
278
|
|
|
260
279
|
---
|
|
261
280
|
|
|
@@ -296,12 +315,23 @@ specweave init .
|
|
|
296
315
|
|
|
297
316
|
## Key Features
|
|
298
317
|
|
|
318
|
+
### Strategic Init - AI-Powered Architecture Planning (NEW!)
|
|
319
|
+
|
|
320
|
+
- 🎯 **Research-Driven Discovery** - Answer 6 phases of questions about your product
|
|
321
|
+
- 🏗️ **Architecture Recommendations** - Tech stack, scaling strategy, cost projections
|
|
322
|
+
- 🔒 **Compliance Detection** - Auto-detects 30+ standards (HIPAA, GDPR, SOC2, etc.)
|
|
323
|
+
- 👥 **Smart Team Planning** - Current and future team structure, hiring roadmap
|
|
324
|
+
- ☁️ **Cloud Credits Discovery** - AWS Activate, Azure Startup, GCP eligibility
|
|
325
|
+
- 📦 **Repository Selection** - Batch select 1-100+ repos with intelligent routing
|
|
326
|
+
|
|
327
|
+
### Production Features
|
|
328
|
+
|
|
299
329
|
- 🤖 **AI-Native Enterprise Sync** - Claude updates JIRA/GitHub/ADO automatically (bidirectional!)
|
|
300
330
|
- 📚 **Living Documentation** - Auto-updates after every task (no manual sync!)
|
|
301
331
|
- 🧪 **Test-Aware Planning** - Embedded tests in BDD format (Given/When/Then)
|
|
302
332
|
- 🎯 **Disciplined Progress** - Can't start increment N+1 until N is DONE
|
|
303
333
|
- ⏸️ **Intelligent Pausing** - Auto-detects blockers, pauses with context, resumes when ready
|
|
304
|
-
- 🔄 **Smart Reopen
|
|
334
|
+
- 🔄 **Smart Reopen** - Report "broken" → Auto-detects what to reopen, respects WIP limits
|
|
305
335
|
- 👥 **Multi-Project Tracking** - Unlimited JIRA/ADO/GitHub repos, intelligent routing
|
|
306
336
|
- 🤖 **AI Agents** - PM, Architect, Quality Judge guide your work
|
|
307
337
|
- 🔧 **CI/CD Auto-Fix** - Workflow failures auto-fixed by Claude (just mention `@claude`)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates that completed tasks have actual code implementation.
|
|
5
|
+
* Prevents marking tasks as complete when:
|
|
6
|
+
* - Files don't exist
|
|
7
|
+
* - Files are empty or have trivial content
|
|
8
|
+
* - Implementation is incomplete
|
|
9
|
+
*
|
|
10
|
+
* Used by ThreeLayerSyncManager to enforce code-completion discipline.
|
|
11
|
+
*
|
|
12
|
+
* @module CodeValidator
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* File validation result
|
|
16
|
+
*/
|
|
17
|
+
export interface FileValidationResult {
|
|
18
|
+
path: string;
|
|
19
|
+
exists: boolean;
|
|
20
|
+
hasContent: boolean;
|
|
21
|
+
lineCount: number;
|
|
22
|
+
reason?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Task validation result
|
|
26
|
+
*/
|
|
27
|
+
export interface TaskValidationResult {
|
|
28
|
+
taskId: string;
|
|
29
|
+
valid: boolean;
|
|
30
|
+
files: FileValidationResult[];
|
|
31
|
+
reason?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* CodeValidator options
|
|
35
|
+
*/
|
|
36
|
+
export interface CodeValidatorOptions {
|
|
37
|
+
minLines?: number;
|
|
38
|
+
minChars?: number;
|
|
39
|
+
projectRoot?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare class CodeValidator {
|
|
42
|
+
private options;
|
|
43
|
+
constructor(options?: CodeValidatorOptions);
|
|
44
|
+
/**
|
|
45
|
+
* Validate that code exists for a task
|
|
46
|
+
*
|
|
47
|
+
* Extracts file paths from task description and verifies:
|
|
48
|
+
* 1. Files exist
|
|
49
|
+
* 2. Files have meaningful content
|
|
50
|
+
* 3. Files are not just stubs
|
|
51
|
+
*
|
|
52
|
+
* @param taskDescription - Task description with file paths
|
|
53
|
+
* @param taskId - Task ID for error messages
|
|
54
|
+
* @returns Validation result
|
|
55
|
+
*/
|
|
56
|
+
validateTask(taskDescription: string, taskId: string): Promise<TaskValidationResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Validate a single file
|
|
59
|
+
*
|
|
60
|
+
* @param filePath - Path to file (relative or absolute)
|
|
61
|
+
* @returns File validation result
|
|
62
|
+
*/
|
|
63
|
+
validateFile(filePath: string): Promise<FileValidationResult>;
|
|
64
|
+
/**
|
|
65
|
+
* Extract file paths from task description
|
|
66
|
+
*
|
|
67
|
+
* Supports multiple formats:
|
|
68
|
+
* - **Files**: src/foo.ts, src/bar.ts
|
|
69
|
+
* - **Files to create**: src/foo.ts
|
|
70
|
+
* - **Files to modify**: src/bar.ts
|
|
71
|
+
* - Inline code blocks with file paths
|
|
72
|
+
*
|
|
73
|
+
* @param description - Task description text
|
|
74
|
+
* @returns Array of file paths
|
|
75
|
+
*/
|
|
76
|
+
extractFilePaths(description: string): string[];
|
|
77
|
+
/**
|
|
78
|
+
* Batch validate multiple tasks
|
|
79
|
+
*
|
|
80
|
+
* @param tasks - Array of {taskId, description}
|
|
81
|
+
* @returns Array of validation results
|
|
82
|
+
*/
|
|
83
|
+
validateTasks(tasks: Array<{
|
|
84
|
+
taskId: string;
|
|
85
|
+
description: string;
|
|
86
|
+
}>): Promise<TaskValidationResult[]>;
|
|
87
|
+
/**
|
|
88
|
+
* Get summary of validation results
|
|
89
|
+
*
|
|
90
|
+
* @param results - Array of task validation results
|
|
91
|
+
* @returns Summary statistics
|
|
92
|
+
*/
|
|
93
|
+
summarizeResults(results: TaskValidationResult[]): {
|
|
94
|
+
total: number;
|
|
95
|
+
valid: number;
|
|
96
|
+
invalid: number;
|
|
97
|
+
noFiles: number;
|
|
98
|
+
invalidTasks: string[];
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=CodeValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeValidator.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/CodeValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAiC;gBAEpC,OAAO,GAAE,oBAAyB;IAQ9C;;;;;;;;;;;OAWG;IACG,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAsC1F;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA4EnE;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE;IAuC/C;;;;;OAKG;IACG,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAS3G;;;;;OAKG;IACH,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG;QACjD,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB;CAeF"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates that completed tasks have actual code implementation.
|
|
5
|
+
* Prevents marking tasks as complete when:
|
|
6
|
+
* - Files don't exist
|
|
7
|
+
* - Files are empty or have trivial content
|
|
8
|
+
* - Implementation is incomplete
|
|
9
|
+
*
|
|
10
|
+
* Used by ThreeLayerSyncManager to enforce code-completion discipline.
|
|
11
|
+
*
|
|
12
|
+
* @module CodeValidator
|
|
13
|
+
*/
|
|
14
|
+
import fs from 'fs-extra';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
export class CodeValidator {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.options = {
|
|
19
|
+
minLines: options.minLines ?? 3,
|
|
20
|
+
minChars: options.minChars ?? 50,
|
|
21
|
+
projectRoot: options.projectRoot ?? process.cwd()
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validate that code exists for a task
|
|
26
|
+
*
|
|
27
|
+
* Extracts file paths from task description and verifies:
|
|
28
|
+
* 1. Files exist
|
|
29
|
+
* 2. Files have meaningful content
|
|
30
|
+
* 3. Files are not just stubs
|
|
31
|
+
*
|
|
32
|
+
* @param taskDescription - Task description with file paths
|
|
33
|
+
* @param taskId - Task ID for error messages
|
|
34
|
+
* @returns Validation result
|
|
35
|
+
*/
|
|
36
|
+
async validateTask(taskDescription, taskId) {
|
|
37
|
+
const filePaths = this.extractFilePaths(taskDescription);
|
|
38
|
+
if (filePaths.length === 0) {
|
|
39
|
+
// No file paths specified - consider it valid (task might be non-code)
|
|
40
|
+
return {
|
|
41
|
+
taskId,
|
|
42
|
+
valid: true,
|
|
43
|
+
files: [],
|
|
44
|
+
reason: 'No file paths specified in task description'
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const fileResults = [];
|
|
48
|
+
let allValid = true;
|
|
49
|
+
const reasons = [];
|
|
50
|
+
for (const filePath of filePaths) {
|
|
51
|
+
const result = await this.validateFile(filePath);
|
|
52
|
+
fileResults.push(result);
|
|
53
|
+
if (!result.exists) {
|
|
54
|
+
allValid = false;
|
|
55
|
+
reasons.push(`File not found: ${filePath}`);
|
|
56
|
+
}
|
|
57
|
+
else if (!result.hasContent) {
|
|
58
|
+
allValid = false;
|
|
59
|
+
reasons.push(`File has no meaningful content: ${filePath} (${result.reason})`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
taskId,
|
|
64
|
+
valid: allValid,
|
|
65
|
+
files: fileResults,
|
|
66
|
+
reason: reasons.length > 0 ? reasons.join('; ') : undefined
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Validate a single file
|
|
71
|
+
*
|
|
72
|
+
* @param filePath - Path to file (relative or absolute)
|
|
73
|
+
* @returns File validation result
|
|
74
|
+
*/
|
|
75
|
+
async validateFile(filePath) {
|
|
76
|
+
// Resolve relative paths
|
|
77
|
+
const absolutePath = path.isAbsolute(filePath)
|
|
78
|
+
? filePath
|
|
79
|
+
: path.join(this.options.projectRoot, filePath);
|
|
80
|
+
// Check if file exists
|
|
81
|
+
const exists = await fs.pathExists(absolutePath);
|
|
82
|
+
if (!exists) {
|
|
83
|
+
return {
|
|
84
|
+
path: filePath,
|
|
85
|
+
exists: false,
|
|
86
|
+
hasContent: false,
|
|
87
|
+
lineCount: 0,
|
|
88
|
+
reason: 'File does not exist'
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// Read file content
|
|
92
|
+
const content = await fs.readFile(absolutePath, 'utf-8');
|
|
93
|
+
const lines = content.split('\n');
|
|
94
|
+
const nonEmptyLines = lines.filter(line => line.trim().length > 0);
|
|
95
|
+
// Check line count
|
|
96
|
+
if (nonEmptyLines.length < this.options.minLines) {
|
|
97
|
+
return {
|
|
98
|
+
path: filePath,
|
|
99
|
+
exists: true,
|
|
100
|
+
hasContent: false,
|
|
101
|
+
lineCount: nonEmptyLines.length,
|
|
102
|
+
reason: `Only ${nonEmptyLines.length} non-empty lines (minimum: ${this.options.minLines})`
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// Check character count
|
|
106
|
+
const trimmedContent = content.trim();
|
|
107
|
+
if (trimmedContent.length < this.options.minChars) {
|
|
108
|
+
return {
|
|
109
|
+
path: filePath,
|
|
110
|
+
exists: true,
|
|
111
|
+
hasContent: false,
|
|
112
|
+
lineCount: nonEmptyLines.length,
|
|
113
|
+
reason: `Only ${trimmedContent.length} characters (minimum: ${this.options.minChars})`
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// Check for stub patterns (common placeholder patterns)
|
|
117
|
+
const stubPatterns = [
|
|
118
|
+
/^\/\/\s*TODO:/i,
|
|
119
|
+
/^#\s*TODO:/i,
|
|
120
|
+
/^\s*throw new Error\(['"]Not implemented['"]\)/i,
|
|
121
|
+
/^\s*return null;?\s*$/m,
|
|
122
|
+
/^\s*pass\s*$/m, // Python
|
|
123
|
+
/^\s*\.\.\.$/m // TypeScript
|
|
124
|
+
];
|
|
125
|
+
const isStub = stubPatterns.some(pattern => pattern.test(trimmedContent));
|
|
126
|
+
if (isStub) {
|
|
127
|
+
return {
|
|
128
|
+
path: filePath,
|
|
129
|
+
exists: true,
|
|
130
|
+
hasContent: false,
|
|
131
|
+
lineCount: nonEmptyLines.length,
|
|
132
|
+
reason: 'File contains stub/placeholder code'
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// All checks passed
|
|
136
|
+
return {
|
|
137
|
+
path: filePath,
|
|
138
|
+
exists: true,
|
|
139
|
+
hasContent: true,
|
|
140
|
+
lineCount: nonEmptyLines.length
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Extract file paths from task description
|
|
145
|
+
*
|
|
146
|
+
* Supports multiple formats:
|
|
147
|
+
* - **Files**: src/foo.ts, src/bar.ts
|
|
148
|
+
* - **Files to create**: src/foo.ts
|
|
149
|
+
* - **Files to modify**: src/bar.ts
|
|
150
|
+
* - Inline code blocks with file paths
|
|
151
|
+
*
|
|
152
|
+
* @param description - Task description text
|
|
153
|
+
* @returns Array of file paths
|
|
154
|
+
*/
|
|
155
|
+
extractFilePaths(description) {
|
|
156
|
+
const paths = new Set();
|
|
157
|
+
// Pattern 1: **Files**: path1, path2, path3
|
|
158
|
+
const filesMatch = description.match(/\*\*Files\*\*:\s*([^\n]+)/i);
|
|
159
|
+
if (filesMatch) {
|
|
160
|
+
const filePaths = filesMatch[1].split(',').map(p => p.trim());
|
|
161
|
+
filePaths.forEach(p => paths.add(p));
|
|
162
|
+
}
|
|
163
|
+
// Pattern 2: **Files to create**: path1, path2
|
|
164
|
+
const createMatch = description.match(/\*\*Files to create\*\*:\s*([^\n]+)/i);
|
|
165
|
+
if (createMatch) {
|
|
166
|
+
const filePaths = createMatch[1].split(',').map(p => p.trim());
|
|
167
|
+
filePaths.forEach(p => paths.add(p));
|
|
168
|
+
}
|
|
169
|
+
// Pattern 3: **Files to modify**: path1, path2
|
|
170
|
+
const modifyMatch = description.match(/\*\*Files to modify\*\*:\s*([^\n]+)/i);
|
|
171
|
+
if (modifyMatch) {
|
|
172
|
+
const filePaths = modifyMatch[1].split(',').map(p => p.trim());
|
|
173
|
+
filePaths.forEach(p => paths.add(p));
|
|
174
|
+
}
|
|
175
|
+
// Pattern 4: Inline file references (e.g., `src/foo/bar.ts`)
|
|
176
|
+
const inlineMatches = description.matchAll(/`([a-zA-Z0-9_\-./]+\.(ts|js|tsx|jsx|py|java|go|rs|cpp|c|h))`/g);
|
|
177
|
+
for (const match of inlineMatches) {
|
|
178
|
+
paths.add(match[1]);
|
|
179
|
+
}
|
|
180
|
+
// Pattern 5: Markdown list items with file paths
|
|
181
|
+
const listMatches = description.matchAll(/^[-*]\s+([a-zA-Z0-9_\-./]+\.(ts|js|tsx|jsx|py|java|go|rs|cpp|c|h))/gm);
|
|
182
|
+
for (const match of listMatches) {
|
|
183
|
+
paths.add(match[1]);
|
|
184
|
+
}
|
|
185
|
+
return Array.from(paths);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Batch validate multiple tasks
|
|
189
|
+
*
|
|
190
|
+
* @param tasks - Array of {taskId, description}
|
|
191
|
+
* @returns Array of validation results
|
|
192
|
+
*/
|
|
193
|
+
async validateTasks(tasks) {
|
|
194
|
+
// Use parallel validation for performance
|
|
195
|
+
const validationPromises = tasks.map(task => this.validateTask(task.description, task.taskId));
|
|
196
|
+
return Promise.all(validationPromises);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get summary of validation results
|
|
200
|
+
*
|
|
201
|
+
* @param results - Array of task validation results
|
|
202
|
+
* @returns Summary statistics
|
|
203
|
+
*/
|
|
204
|
+
summarizeResults(results) {
|
|
205
|
+
const total = results.length;
|
|
206
|
+
const valid = results.filter(r => r.valid).length;
|
|
207
|
+
const invalid = results.filter(r => !r.valid).length;
|
|
208
|
+
const noFiles = results.filter(r => r.files.length === 0).length;
|
|
209
|
+
const invalidTasks = results.filter(r => !r.valid).map(r => r.taskId);
|
|
210
|
+
return {
|
|
211
|
+
total,
|
|
212
|
+
valid,
|
|
213
|
+
invalid,
|
|
214
|
+
noFiles,
|
|
215
|
+
invalidTasks
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=CodeValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeValidator.js","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/CodeValidator.ts"],"names":[],"mappings":"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"}
|