specweave 0.21.3 → 0.22.2
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 +409 -6
- package/README.md +38 -8
- package/bin/specweave.js +5 -8
- 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/github-client-v2.d.ts +10 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +26 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/plugins/specweave-github/lib/task-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/task-sync.js +7 -0
- package/dist/plugins/specweave-github/lib/task-sync.js.map +1 -1
- 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/cli/commands/migrate-to-profiles.d.ts +1 -0
- package/dist/src/cli/commands/migrate-to-profiles.d.ts.map +1 -1
- package/dist/src/cli/commands/migrate-to-profiles.js +12 -1
- package/dist/src/cli/commands/migrate-to-profiles.js.map +1 -1
- package/dist/src/cli/commands/next-command.d.ts +52 -0
- package/dist/src/cli/commands/next-command.d.ts.map +1 -0
- package/dist/src/cli/commands/next-command.js +204 -0
- package/dist/src/cli/commands/next-command.js.map +1 -0
- package/dist/src/cli/commands/sync-specs.d.ts +16 -0
- package/dist/src/cli/commands/sync-specs.d.ts.map +1 -0
- package/dist/src/cli/commands/sync-specs.js +130 -0
- package/dist/src/cli/commands/sync-specs.js.map +1 -0
- package/dist/src/cli/count-tasks.d.ts +20 -0
- package/dist/src/cli/count-tasks.d.ts.map +1 -0
- package/dist/src/cli/count-tasks.js +50 -0
- package/dist/src/cli/count-tasks.js.map +1 -0
- package/dist/src/config/ConfigManager.d.ts.map +1 -1
- package/dist/src/config/ConfigManager.js +2 -1
- package/dist/src/config/ConfigManager.js.map +1 -1
- package/dist/src/config/types.d.ts +58 -58
- package/dist/src/core/cicd/state-manager.d.ts +8 -0
- package/dist/src/core/cicd/state-manager.d.ts.map +1 -1
- package/dist/src/core/cicd/state-manager.js +60 -15
- package/dist/src/core/cicd/state-manager.js.map +1 -1
- package/dist/src/core/cost-tracker.d.ts.map +1 -1
- package/dist/src/core/cost-tracker.js +2 -1
- package/dist/src/core/cost-tracker.js.map +1 -1
- package/dist/src/core/iac/template-engine.d.ts.map +1 -1
- package/dist/src/core/iac/template-engine.js +28 -0
- package/dist/src/core/iac/template-engine.js.map +1 -1
- package/dist/src/core/iac/template-generator.d.ts +53 -0
- package/dist/src/core/iac/template-generator.d.ts.map +1 -0
- package/dist/src/core/iac/template-generator.js +125 -0
- package/dist/src/core/iac/template-generator.js.map +1 -0
- package/dist/src/core/increment/status-auto-transition.js +3 -3
- package/dist/src/core/increment/status-auto-transition.js.map +1 -1
- package/dist/src/core/living-docs/CodeValidator.js +1 -1
- package/dist/src/core/living-docs/CodeValidator.js.map +1 -1
- 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/content-distributor.d.ts.map +1 -1
- package/dist/src/core/living-docs/content-distributor.js +11 -1
- package/dist/src/core/living-docs/content-distributor.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +166 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -0
- package/dist/src/core/living-docs/living-docs-sync.js +726 -0
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -0
- 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/living-docs/task-project-specific-generator.d.ts +7 -3
- package/dist/src/core/living-docs/task-project-specific-generator.d.ts.map +1 -1
- package/dist/src/core/living-docs/task-project-specific-generator.js +40 -24
- package/dist/src/core/living-docs/task-project-specific-generator.js.map +1 -1
- package/dist/src/core/plugin-loader.d.ts +7 -0
- package/dist/src/core/plugin-loader.d.ts.map +1 -1
- package/dist/src/core/plugin-loader.js +18 -1
- package/dist/src/core/plugin-loader.js.map +1 -1
- package/dist/src/core/serverless/platform-data-loader.d.ts +8 -0
- package/dist/src/core/serverless/platform-data-loader.d.ts.map +1 -1
- package/dist/src/core/serverless/platform-data-loader.js +14 -0
- package/dist/src/core/serverless/platform-data-loader.js.map +1 -1
- package/dist/src/core/serverless/types.d.ts +1 -1
- package/dist/src/core/serverless/types.d.ts.map +1 -1
- package/dist/src/core/status-line/status-line-manager.d.ts +6 -2
- package/dist/src/core/status-line/status-line-manager.d.ts.map +1 -1
- package/dist/src/core/status-line/status-line-manager.js +11 -5
- package/dist/src/core/status-line/status-line-manager.js.map +1 -1
- package/dist/src/core/status-line/task-counter.d.ts +69 -0
- package/dist/src/core/status-line/task-counter.d.ts.map +1 -0
- package/dist/src/core/status-line/task-counter.js +107 -0
- package/dist/src/core/status-line/task-counter.js.map +1 -0
- 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/core/workflow/autonomous-executor.d.ts +111 -0
- package/dist/src/core/workflow/autonomous-executor.d.ts.map +1 -0
- package/dist/src/core/workflow/autonomous-executor.js +275 -0
- package/dist/src/core/workflow/autonomous-executor.js.map +1 -0
- package/dist/src/core/workflow/backlog-scanner.d.ts +94 -0
- package/dist/src/core/workflow/backlog-scanner.d.ts.map +1 -0
- package/dist/src/core/workflow/backlog-scanner.js +170 -0
- package/dist/src/core/workflow/backlog-scanner.js.map +1 -0
- package/dist/src/core/workflow/command-invoker.d.ts +86 -0
- package/dist/src/core/workflow/command-invoker.d.ts.map +1 -0
- package/dist/src/core/workflow/command-invoker.js +131 -0
- package/dist/src/core/workflow/command-invoker.js.map +1 -0
- package/dist/src/core/workflow/cost-estimator.d.ts +120 -0
- package/dist/src/core/workflow/cost-estimator.d.ts.map +1 -0
- package/dist/src/core/workflow/cost-estimator.js +222 -0
- package/dist/src/core/workflow/cost-estimator.js.map +1 -0
- package/dist/src/core/workflow/index.d.ts +20 -0
- package/dist/src/core/workflow/index.d.ts.map +1 -0
- package/dist/src/core/workflow/index.js +24 -0
- package/dist/src/core/workflow/index.js.map +1 -0
- package/dist/src/core/workflow/state-manager.d.ts +107 -0
- package/dist/src/core/workflow/state-manager.d.ts.map +1 -0
- package/dist/src/core/workflow/state-manager.js +126 -0
- package/dist/src/core/workflow/state-manager.js.map +1 -0
- package/dist/src/core/workflow/workflow-orchestrator.d.ts +93 -0
- package/dist/src/core/workflow/workflow-orchestrator.d.ts.map +1 -0
- package/dist/src/core/workflow/workflow-orchestrator.js +195 -0
- package/dist/src/core/workflow/workflow-orchestrator.js.map +1 -0
- 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/architecture/types.d.ts +10 -10
- package/dist/src/init/research/src/config/types.d.ts +8 -8
- package/dist/src/metrics/dora-calculator.js +2 -2
- package/dist/src/metrics/dora-calculator.js.map +1 -1
- package/dist/src/utils/pricing-constants.d.ts +5 -2
- package/dist/src/utils/pricing-constants.d.ts.map +1 -1
- package/dist/src/utils/pricing-constants.js +3 -2
- package/dist/src/utils/pricing-constants.js.map +1 -1
- package/package.json +9 -8
- package/plugins/specweave/agents/infrastructure/AGENT.md +88 -46
- package/plugins/specweave/agents/pm/AGENT.md +58 -1
- package/plugins/specweave/commands/specweave-archive-features.md +1 -1
- package/plugins/specweave/commands/specweave-archive-increments.md +1 -1
- package/plugins/specweave/commands/specweave-check-hooks.md +5 -0
- package/plugins/specweave/commands/specweave-done.md +12 -0
- package/plugins/specweave/commands/specweave-plan.md +1 -1
- package/plugins/specweave/commands/specweave-progress.md +108 -379
- package/plugins/specweave/commands/specweave-reopen.md +1 -1
- package/plugins/specweave/commands/specweave-restore-feature.md +1 -1
- package/plugins/specweave/commands/specweave-sync-specs.md +20 -48
- package/plugins/specweave/hooks/lib/update-status-line.sh +44 -35
- package/plugins/specweave/hooks/lib/validate-spec-status.sh +163 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +17 -35
- package/plugins/specweave/lib/hooks/update-tasks-md.js +52 -9
- package/plugins/specweave/lib/hooks/update-tasks-md.ts +77 -16
- package/plugins/specweave/templates/iac/aws-lambda/defaults.json +24 -0
- package/plugins/specweave/templates/iac/aws-lambda/templates/README.md.hbs +260 -0
- package/plugins/specweave/templates/iac/aws-lambda/templates/environments/dev.tfvars.hbs +34 -0
- package/plugins/specweave/templates/iac/aws-lambda/templates/environments/prod.tfvars.hbs +37 -0
- package/plugins/specweave/templates/iac/aws-lambda/templates/environments/staging.tfvars.hbs +35 -0
- package/plugins/specweave/templates/iac/aws-lambda/templates/outputs.tf.hbs +77 -0
- package/plugins/specweave/templates/iac/aws-lambda/templates/providers.tf.hbs +36 -0
- package/plugins/specweave/templates/iac/aws-lambda/templates/variables.tf.hbs +115 -0
- package/plugins/specweave/templates/iac/azure-functions/defaults.json +25 -0
- package/plugins/specweave/templates/iac/azure-functions/templates/README.md.hbs +268 -0
- package/plugins/specweave/templates/iac/azure-functions/templates/environments/dev.tfvars.hbs +34 -0
- package/plugins/specweave/templates/iac/azure-functions/templates/environments/prod.tfvars.hbs +46 -0
- package/plugins/specweave/templates/iac/azure-functions/templates/environments/staging.tfvars.hbs +34 -0
- package/plugins/specweave/templates/iac/azure-functions/templates/main.tf.hbs +225 -0
- package/plugins/specweave/templates/iac/azure-functions/templates/outputs.tf.hbs +89 -0
- package/plugins/specweave/templates/iac/azure-functions/templates/provider.tf.hbs +27 -0
- package/plugins/specweave/templates/iac/azure-functions/templates/providers.tf.hbs +35 -0
- package/plugins/specweave/templates/iac/azure-functions/templates/variables.tf.hbs +124 -0
- package/plugins/specweave/templates/iac/firebase/defaults.json +29 -0
- package/plugins/specweave/templates/iac/firebase/templates/README.md.hbs +35 -0
- package/plugins/specweave/templates/iac/firebase/templates/environments/dev.tfvars.hbs +7 -0
- package/plugins/specweave/templates/iac/firebase/templates/environments/prod.tfvars.hbs +7 -0
- package/plugins/specweave/templates/iac/firebase/templates/environments/staging.tfvars.hbs +7 -0
- package/plugins/specweave/templates/iac/firebase/templates/main.tf.hbs +90 -0
- package/plugins/specweave/templates/iac/firebase/templates/outputs.tf.hbs +15 -0
- package/plugins/specweave/templates/iac/firebase/templates/providers.tf.hbs +23 -0
- package/plugins/specweave/templates/iac/firebase/templates/variables.tf.hbs +42 -0
- package/plugins/specweave/templates/iac/gcp-cloud-functions/defaults.json +26 -0
- package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/README.md.hbs +299 -0
- package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/environments/dev.tfvars.hbs +36 -0
- package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/environments/prod.tfvars.hbs +48 -0
- package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/environments/staging.tfvars.hbs +41 -0
- package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/main.tf.hbs +192 -0
- package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/outputs.tf.hbs +66 -0
- package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/providers.tf.hbs +25 -0
- package/plugins/specweave/templates/iac/gcp-cloud-functions/templates/variables.tf.hbs +119 -0
- package/plugins/specweave/templates/iac/supabase/defaults.json +15 -0
- package/plugins/specweave/templates/iac/supabase/templates/README.md.hbs +46 -0
- package/plugins/specweave/templates/iac/supabase/templates/main.tf.hbs +50 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-github/agents/github-manager/AGENT.md +39 -7
- package/plugins/specweave-github/commands/specweave-github-create-issue.md +5 -5
- 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/github-client-v2.js +29 -0
- package/plugins/specweave-github/lib/github-client-v2.ts +30 -0
- package/plugins/specweave-github/lib/task-sync.js +4 -0
- package/plugins/specweave-github/lib/task-sync.ts +7 -0
- package/plugins/specweave-github/lib/types.ts +38 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +3222 -0
- package/src/templates/AGENTS.md.template +22 -1
- package/src/templates/CLAUDE.md.template +31 -0
- package/dist/src/core/living-docs/ThreeLayerSyncManager.d.ts +0 -116
- package/dist/src/core/living-docs/ThreeLayerSyncManager.d.ts.map +0 -1
- package/dist/src/core/living-docs/ThreeLayerSyncManager.js +0 -356
- package/dist/src/core/living-docs/ThreeLayerSyncManager.js.map +0 -1
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
# GitHub Manager Agent
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
⚠️ **DEPRECATED: Use Living Docs Sync Instead** ⚠️
|
|
4
|
+
|
|
5
|
+
**CRITICAL**: This agent creates GitHub issues using the OLD `[Increment XXXX]` format,
|
|
6
|
+
which violates SpecWeave's data flow architecture.
|
|
7
|
+
|
|
8
|
+
**CORRECT DATA FLOW**:
|
|
9
|
+
```
|
|
10
|
+
Increment → Living Docs → GitHub
|
|
11
|
+
(source of truth)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**USE INSTEAD**:
|
|
15
|
+
- `/specweave:sync-docs update` - Generate living docs from increments
|
|
16
|
+
- `/specweave-github:sync` - Sync living docs to GitHub Issues
|
|
17
|
+
- Result: Issues use correct `US-XXX` or `FS-YY-MM-DD` format
|
|
18
|
+
|
|
19
|
+
**WHY THIS IS DEPRECATED**:
|
|
20
|
+
1. Creates issues with `[Increment XXXX]` format (rejected by validation)
|
|
21
|
+
2. Bypasses living docs (source of truth)
|
|
22
|
+
3. No traceability to User Stories/Feature Specs
|
|
23
|
+
4. Cannot sync bidirectionally with living docs
|
|
24
|
+
|
|
25
|
+
**IF YOU USE THIS AGENT**: GitHub client will REJECT issue creation with error:
|
|
26
|
+
```
|
|
27
|
+
❌ DEPRECATED FORMAT DETECTED: "[Increment 0043] Title"
|
|
28
|
+
GitHub issues MUST use living docs format:
|
|
29
|
+
✅ CORRECT: "US-XXX: Title" (User Story)
|
|
30
|
+
✅ CORRECT: "FS-YY-MM-DD: Title" (Feature Spec)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
**Role**: GitHub integration specialist for SpecWeave increments (DEPRECATED)
|
|
4
36
|
|
|
5
37
|
**Expertise**: GitHub CLI, GitHub API, issue management, project boards, automation, webhooks, Actions
|
|
6
38
|
|
|
@@ -143,9 +175,9 @@ Invoke the github-manager agent (via Task tool) for:
|
|
|
143
175
|
### Issue Management
|
|
144
176
|
|
|
145
177
|
```bash
|
|
146
|
-
# Create issue
|
|
178
|
+
# ❌ DEPRECATED - Create issue (OLD FORMAT - DO NOT USE)
|
|
147
179
|
gh issue create \
|
|
148
|
-
--title "[Increment 0004] Plugin Architecture" \
|
|
180
|
+
--title "[Increment 0004] Plugin Architecture" \ # ❌ DEPRECATED
|
|
149
181
|
--body "$(cat issue-body.md)" \
|
|
150
182
|
--label "specweave,increment,P1" \
|
|
151
183
|
--milestone "v0.4.0"
|
|
@@ -384,10 +416,10 @@ When a new increment is created:
|
|
|
384
416
|
- Parse `tasks.md` for task checklist
|
|
385
417
|
- Format using issue template
|
|
386
418
|
|
|
387
|
-
4. **Create GitHub Issue**
|
|
419
|
+
4. **Create GitHub Issue** (❌ DEPRECATED - DO NOT USE)
|
|
388
420
|
```bash
|
|
389
421
|
gh issue create \
|
|
390
|
-
--title "[Increment 0004] Plugin Architecture" \
|
|
422
|
+
--title "[Increment 0004] Plugin Architecture" \ # ❌ DEPRECATED
|
|
391
423
|
--body "$(cat /tmp/issue-body.md)" \
|
|
392
424
|
--label "specweave,increment,P1" \
|
|
393
425
|
--milestone "v0.4.0"
|
|
@@ -680,9 +712,9 @@ GitHub Manager Agent:
|
|
|
680
712
|
5. Updating metadata...
|
|
681
713
|
✓ Saved to .metadata.yaml
|
|
682
714
|
|
|
683
|
-
✅ GitHub Issue Created!
|
|
715
|
+
✅ GitHub Issue Created! (❌ DEPRECATED FORMAT)
|
|
684
716
|
|
|
685
|
-
Issue #130: [Increment 0004] Plugin Architecture
|
|
717
|
+
Issue #130: [Increment 0004] Plugin Architecture # ❌ DEPRECATED
|
|
686
718
|
URL: https://github.com/owner/repo/issues/130
|
|
687
719
|
|
|
688
720
|
You can now:
|
|
@@ -175,9 +175,9 @@ Creating issue...
|
|
|
175
175
|
✓ Milestone set: v0.4.0
|
|
176
176
|
✓ Metadata updated
|
|
177
177
|
|
|
178
|
-
✅ GitHub Issue Created!
|
|
178
|
+
✅ GitHub Issue Created! (❌ DEPRECATED FORMAT)
|
|
179
179
|
|
|
180
|
-
Issue #130: [Increment 0004] Plugin Architecture
|
|
180
|
+
Issue #130: [Increment 0004] Plugin Architecture # ❌ DEPRECATED
|
|
181
181
|
URL: https://github.com/owner/repo/issues/130
|
|
182
182
|
|
|
183
183
|
Auto-sync enabled: progress will update automatically after each task.
|
|
@@ -274,15 +274,15 @@ Preview issue body before creating:
|
|
|
274
274
|
|
|
275
275
|
Output:
|
|
276
276
|
```
|
|
277
|
-
📄 Preview: Issue body for increment 0004
|
|
277
|
+
📄 Preview: Issue body for increment 0004 (❌ DEPRECATED FORMAT)
|
|
278
278
|
|
|
279
|
-
Title: [Increment 0004] Plugin Architecture
|
|
279
|
+
Title: [Increment 0004] Plugin Architecture # ❌ DEPRECATED
|
|
280
280
|
Labels: specweave, increment, P1
|
|
281
281
|
Milestone: v0.4.0
|
|
282
282
|
|
|
283
283
|
Body:
|
|
284
284
|
---
|
|
285
|
-
# [Increment 0004] Plugin Architecture
|
|
285
|
+
# [Increment 0004] Plugin Architecture # ❌ DEPRECATED
|
|
286
286
|
|
|
287
287
|
**Status**: Planning
|
|
288
288
|
**Priority**: P1
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
class CodeValidator {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.options = {
|
|
6
|
+
minLines: options.minLines ?? 3,
|
|
7
|
+
minChars: options.minChars ?? 50,
|
|
8
|
+
projectRoot: options.projectRoot ?? process.cwd()
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Validate that code exists for a task
|
|
13
|
+
*
|
|
14
|
+
* Extracts file paths from task description and verifies:
|
|
15
|
+
* 1. Files exist
|
|
16
|
+
* 2. Files have meaningful content
|
|
17
|
+
* 3. Files are not just stubs
|
|
18
|
+
*
|
|
19
|
+
* @param taskDescription - Task description with file paths
|
|
20
|
+
* @param taskId - Task ID for error messages
|
|
21
|
+
* @returns Validation result
|
|
22
|
+
*/
|
|
23
|
+
async validateTask(taskDescription, taskId) {
|
|
24
|
+
const filePaths = this.extractFilePaths(taskDescription);
|
|
25
|
+
if (filePaths.length === 0) {
|
|
26
|
+
return {
|
|
27
|
+
taskId,
|
|
28
|
+
valid: true,
|
|
29
|
+
files: [],
|
|
30
|
+
reason: "No file paths specified in task description"
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const fileResults = [];
|
|
34
|
+
let allValid = true;
|
|
35
|
+
const reasons = [];
|
|
36
|
+
for (const filePath of filePaths) {
|
|
37
|
+
const result = await this.validateFile(filePath);
|
|
38
|
+
fileResults.push(result);
|
|
39
|
+
if (!result.exists) {
|
|
40
|
+
allValid = false;
|
|
41
|
+
reasons.push(`File not found: ${filePath}`);
|
|
42
|
+
} else if (!result.hasContent) {
|
|
43
|
+
allValid = false;
|
|
44
|
+
reasons.push(`File has no meaningful content: ${filePath} (${result.reason})`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
taskId,
|
|
49
|
+
valid: allValid,
|
|
50
|
+
files: fileResults,
|
|
51
|
+
reason: reasons.length > 0 ? reasons.join("; ") : void 0
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validate a single file
|
|
56
|
+
*
|
|
57
|
+
* @param filePath - Path to file (relative or absolute)
|
|
58
|
+
* @returns File validation result
|
|
59
|
+
*/
|
|
60
|
+
async validateFile(filePath) {
|
|
61
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(this.options.projectRoot, filePath);
|
|
62
|
+
const exists = await fs.pathExists(absolutePath);
|
|
63
|
+
if (!exists) {
|
|
64
|
+
return {
|
|
65
|
+
path: filePath,
|
|
66
|
+
exists: false,
|
|
67
|
+
hasContent: false,
|
|
68
|
+
lineCount: 0,
|
|
69
|
+
reason: "File does not exist"
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const content = await fs.readFile(absolutePath, "utf-8");
|
|
73
|
+
const lines = content.split("\n");
|
|
74
|
+
const nonEmptyLines = lines.filter((line) => line.trim().length > 0);
|
|
75
|
+
if (nonEmptyLines.length < this.options.minLines) {
|
|
76
|
+
return {
|
|
77
|
+
path: filePath,
|
|
78
|
+
exists: true,
|
|
79
|
+
hasContent: false,
|
|
80
|
+
lineCount: nonEmptyLines.length,
|
|
81
|
+
reason: `Only ${nonEmptyLines.length} non-empty lines (minimum: ${this.options.minLines})`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const trimmedContent = content.trim();
|
|
85
|
+
if (trimmedContent.length < this.options.minChars) {
|
|
86
|
+
return {
|
|
87
|
+
path: filePath,
|
|
88
|
+
exists: true,
|
|
89
|
+
hasContent: false,
|
|
90
|
+
lineCount: nonEmptyLines.length,
|
|
91
|
+
reason: `Only ${trimmedContent.length} characters (minimum: ${this.options.minChars})`
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const stubPatterns = [
|
|
95
|
+
/^\/\/\s*TODO:/i,
|
|
96
|
+
/^#\s*TODO:/i,
|
|
97
|
+
/^\s*throw new Error\(['"]Not implemented['"]\)/i,
|
|
98
|
+
/^\s*return null;?\s*$/m,
|
|
99
|
+
/^\s*pass\s*$/m,
|
|
100
|
+
// Python
|
|
101
|
+
/^\s*\.\.\.$/m
|
|
102
|
+
// TypeScript
|
|
103
|
+
];
|
|
104
|
+
const isStub = stubPatterns.some((pattern) => pattern.test(trimmedContent));
|
|
105
|
+
if (isStub) {
|
|
106
|
+
return {
|
|
107
|
+
path: filePath,
|
|
108
|
+
exists: true,
|
|
109
|
+
hasContent: false,
|
|
110
|
+
lineCount: nonEmptyLines.length,
|
|
111
|
+
reason: "File contains stub/placeholder code"
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
path: filePath,
|
|
116
|
+
exists: true,
|
|
117
|
+
hasContent: true,
|
|
118
|
+
lineCount: nonEmptyLines.length
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Extract file paths from task description
|
|
123
|
+
*
|
|
124
|
+
* Supports multiple formats:
|
|
125
|
+
* - **Files**: src/foo.ts, src/bar.ts
|
|
126
|
+
* - **Files to create**: src/foo.ts
|
|
127
|
+
* - **Files to modify**: src/bar.ts
|
|
128
|
+
* - Inline code blocks with file paths
|
|
129
|
+
*
|
|
130
|
+
* @param description - Task description text
|
|
131
|
+
* @returns Array of file paths
|
|
132
|
+
*/
|
|
133
|
+
extractFilePaths(description) {
|
|
134
|
+
const paths = /* @__PURE__ */ new Set();
|
|
135
|
+
const filesMatch = description.match(/\*\*Files\*\*:\s*([^\n]+)/i);
|
|
136
|
+
if (filesMatch) {
|
|
137
|
+
const filePaths = filesMatch[1].split(",").map((p) => p.trim());
|
|
138
|
+
filePaths.forEach((p) => paths.add(p));
|
|
139
|
+
}
|
|
140
|
+
const createMatch = description.match(/\*\*Files to create\*\*:\s*([^\n]+)/i);
|
|
141
|
+
if (createMatch) {
|
|
142
|
+
const filePaths = createMatch[1].split(",").map((p) => p.trim());
|
|
143
|
+
filePaths.forEach((p) => paths.add(p));
|
|
144
|
+
}
|
|
145
|
+
const modifyMatch = description.match(/\*\*Files to modify\*\*:\s*([^\n]+)/i);
|
|
146
|
+
if (modifyMatch) {
|
|
147
|
+
const filePaths = modifyMatch[1].split(",").map((p) => p.trim());
|
|
148
|
+
filePaths.forEach((p) => paths.add(p));
|
|
149
|
+
}
|
|
150
|
+
const inlineMatches = description.matchAll(/`([a-zA-Z0-9_\-./]+\.(ts|js|tsx|jsx|py|java|go|rs|cpp|c|h))`/g);
|
|
151
|
+
for (const match of inlineMatches) {
|
|
152
|
+
paths.add(match[1]);
|
|
153
|
+
}
|
|
154
|
+
const listMatches = description.matchAll(/^[-*]\s+([a-zA-Z0-9_\-./]+\.(ts|js|tsx|jsx|py|java|go|rs|cpp|c|h))/gm);
|
|
155
|
+
for (const match of listMatches) {
|
|
156
|
+
paths.add(match[1]);
|
|
157
|
+
}
|
|
158
|
+
return Array.from(paths);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Batch validate multiple tasks
|
|
162
|
+
*
|
|
163
|
+
* @param tasks - Array of {taskId, description}
|
|
164
|
+
* @returns Array of validation results
|
|
165
|
+
*/
|
|
166
|
+
async validateTasks(tasks) {
|
|
167
|
+
const validationPromises = tasks.map(
|
|
168
|
+
(task) => this.validateTask(task.description, task.taskId)
|
|
169
|
+
);
|
|
170
|
+
return Promise.all(validationPromises);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get summary of validation results
|
|
174
|
+
*
|
|
175
|
+
* @param results - Array of task validation results
|
|
176
|
+
* @returns Summary statistics
|
|
177
|
+
*/
|
|
178
|
+
summarizeResults(results) {
|
|
179
|
+
const total = results.length;
|
|
180
|
+
const valid = results.filter((r) => r.valid).length;
|
|
181
|
+
const invalid = results.filter((r) => !r.valid).length;
|
|
182
|
+
const noFiles = results.filter((r) => r.files.length === 0).length;
|
|
183
|
+
const invalidTasks = results.filter((r) => !r.valid).map((r) => r.taskId);
|
|
184
|
+
return {
|
|
185
|
+
total,
|
|
186
|
+
valid,
|
|
187
|
+
invalid,
|
|
188
|
+
noFiles,
|
|
189
|
+
invalidTasks
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
export {
|
|
194
|
+
CodeValidator
|
|
195
|
+
};
|
|
@@ -0,0 +1,284 @@
|
|
|
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 GitHub sync to enforce code-completion discipline.
|
|
11
|
+
*
|
|
12
|
+
* @module CodeValidator
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import fs from 'fs-extra';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* File validation result
|
|
20
|
+
*/
|
|
21
|
+
export interface FileValidationResult {
|
|
22
|
+
path: string;
|
|
23
|
+
exists: boolean;
|
|
24
|
+
hasContent: boolean;
|
|
25
|
+
lineCount: number;
|
|
26
|
+
reason?: string; // Why validation failed
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Task validation result
|
|
31
|
+
*/
|
|
32
|
+
export interface TaskValidationResult {
|
|
33
|
+
taskId: string;
|
|
34
|
+
valid: boolean;
|
|
35
|
+
files: FileValidationResult[];
|
|
36
|
+
reason?: string; // Summary of why task validation failed
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* CodeValidator options
|
|
41
|
+
*/
|
|
42
|
+
export interface CodeValidatorOptions {
|
|
43
|
+
minLines?: number; // Minimum lines for a file to be considered non-empty (default: 3)
|
|
44
|
+
minChars?: number; // Minimum characters for meaningful content (default: 50)
|
|
45
|
+
projectRoot?: string; // Project root for resolving relative paths
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class CodeValidator {
|
|
49
|
+
private options: Required<CodeValidatorOptions>;
|
|
50
|
+
|
|
51
|
+
constructor(options: CodeValidatorOptions = {}) {
|
|
52
|
+
this.options = {
|
|
53
|
+
minLines: options.minLines ?? 3,
|
|
54
|
+
minChars: options.minChars ?? 50,
|
|
55
|
+
projectRoot: options.projectRoot ?? process.cwd()
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Validate that code exists for a task
|
|
61
|
+
*
|
|
62
|
+
* Extracts file paths from task description and verifies:
|
|
63
|
+
* 1. Files exist
|
|
64
|
+
* 2. Files have meaningful content
|
|
65
|
+
* 3. Files are not just stubs
|
|
66
|
+
*
|
|
67
|
+
* @param taskDescription - Task description with file paths
|
|
68
|
+
* @param taskId - Task ID for error messages
|
|
69
|
+
* @returns Validation result
|
|
70
|
+
*/
|
|
71
|
+
async validateTask(taskDescription: string, taskId: string): Promise<TaskValidationResult> {
|
|
72
|
+
const filePaths = this.extractFilePaths(taskDescription);
|
|
73
|
+
|
|
74
|
+
if (filePaths.length === 0) {
|
|
75
|
+
// No file paths specified - consider it valid (task might be non-code)
|
|
76
|
+
return {
|
|
77
|
+
taskId,
|
|
78
|
+
valid: true,
|
|
79
|
+
files: [],
|
|
80
|
+
reason: 'No file paths specified in task description'
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const fileResults: FileValidationResult[] = [];
|
|
85
|
+
let allValid = true;
|
|
86
|
+
const reasons: string[] = [];
|
|
87
|
+
|
|
88
|
+
for (const filePath of filePaths) {
|
|
89
|
+
const result = await this.validateFile(filePath);
|
|
90
|
+
fileResults.push(result);
|
|
91
|
+
|
|
92
|
+
if (!result.exists) {
|
|
93
|
+
allValid = false;
|
|
94
|
+
reasons.push(`File not found: ${filePath}`);
|
|
95
|
+
} else if (!result.hasContent) {
|
|
96
|
+
allValid = false;
|
|
97
|
+
reasons.push(`File has no meaningful content: ${filePath} (${result.reason})`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
taskId,
|
|
103
|
+
valid: allValid,
|
|
104
|
+
files: fileResults,
|
|
105
|
+
reason: reasons.length > 0 ? reasons.join('; ') : undefined
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Validate a single file
|
|
111
|
+
*
|
|
112
|
+
* @param filePath - Path to file (relative or absolute)
|
|
113
|
+
* @returns File validation result
|
|
114
|
+
*/
|
|
115
|
+
async validateFile(filePath: string): Promise<FileValidationResult> {
|
|
116
|
+
// Resolve relative paths
|
|
117
|
+
const absolutePath = path.isAbsolute(filePath)
|
|
118
|
+
? filePath
|
|
119
|
+
: path.join(this.options.projectRoot, filePath);
|
|
120
|
+
|
|
121
|
+
// Check if file exists
|
|
122
|
+
const exists = await fs.pathExists(absolutePath);
|
|
123
|
+
if (!exists) {
|
|
124
|
+
return {
|
|
125
|
+
path: filePath,
|
|
126
|
+
exists: false,
|
|
127
|
+
hasContent: false,
|
|
128
|
+
lineCount: 0,
|
|
129
|
+
reason: 'File does not exist'
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Read file content
|
|
134
|
+
const content = await fs.readFile(absolutePath, 'utf-8');
|
|
135
|
+
const lines = content.split('\n');
|
|
136
|
+
const nonEmptyLines = lines.filter(line => line.trim().length > 0);
|
|
137
|
+
|
|
138
|
+
// Check line count
|
|
139
|
+
if (nonEmptyLines.length < this.options.minLines) {
|
|
140
|
+
return {
|
|
141
|
+
path: filePath,
|
|
142
|
+
exists: true,
|
|
143
|
+
hasContent: false,
|
|
144
|
+
lineCount: nonEmptyLines.length,
|
|
145
|
+
reason: `Only ${nonEmptyLines.length} non-empty lines (minimum: ${this.options.minLines})`
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Check character count
|
|
150
|
+
const trimmedContent = content.trim();
|
|
151
|
+
if (trimmedContent.length < this.options.minChars) {
|
|
152
|
+
return {
|
|
153
|
+
path: filePath,
|
|
154
|
+
exists: true,
|
|
155
|
+
hasContent: false,
|
|
156
|
+
lineCount: nonEmptyLines.length,
|
|
157
|
+
reason: `Only ${trimmedContent.length} characters (minimum: ${this.options.minChars})`
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Check for stub patterns (common placeholder patterns)
|
|
162
|
+
const stubPatterns = [
|
|
163
|
+
/^\/\/\s*TODO:/i,
|
|
164
|
+
/^#\s*TODO:/i,
|
|
165
|
+
/^\s*throw new Error\(['"]Not implemented['"]\)/i,
|
|
166
|
+
/^\s*return null;?\s*$/m,
|
|
167
|
+
/^\s*pass\s*$/m, // Python
|
|
168
|
+
/^\s*\.\.\.$/m // TypeScript
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
const isStub = stubPatterns.some(pattern => pattern.test(trimmedContent));
|
|
172
|
+
if (isStub) {
|
|
173
|
+
return {
|
|
174
|
+
path: filePath,
|
|
175
|
+
exists: true,
|
|
176
|
+
hasContent: false,
|
|
177
|
+
lineCount: nonEmptyLines.length,
|
|
178
|
+
reason: 'File contains stub/placeholder code'
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// All checks passed
|
|
183
|
+
return {
|
|
184
|
+
path: filePath,
|
|
185
|
+
exists: true,
|
|
186
|
+
hasContent: true,
|
|
187
|
+
lineCount: nonEmptyLines.length
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Extract file paths from task description
|
|
193
|
+
*
|
|
194
|
+
* Supports multiple formats:
|
|
195
|
+
* - **Files**: src/foo.ts, src/bar.ts
|
|
196
|
+
* - **Files to create**: src/foo.ts
|
|
197
|
+
* - **Files to modify**: src/bar.ts
|
|
198
|
+
* - Inline code blocks with file paths
|
|
199
|
+
*
|
|
200
|
+
* @param description - Task description text
|
|
201
|
+
* @returns Array of file paths
|
|
202
|
+
*/
|
|
203
|
+
extractFilePaths(description: string): string[] {
|
|
204
|
+
const paths: Set<string> = new Set();
|
|
205
|
+
|
|
206
|
+
// Pattern 1: **Files**: path1, path2, path3
|
|
207
|
+
const filesMatch = description.match(/\*\*Files\*\*:\s*([^\n]+)/i);
|
|
208
|
+
if (filesMatch) {
|
|
209
|
+
const filePaths = filesMatch[1].split(',').map(p => p.trim());
|
|
210
|
+
filePaths.forEach(p => paths.add(p));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Pattern 2: **Files to create**: path1, path2
|
|
214
|
+
const createMatch = description.match(/\*\*Files to create\*\*:\s*([^\n]+)/i);
|
|
215
|
+
if (createMatch) {
|
|
216
|
+
const filePaths = createMatch[1].split(',').map(p => p.trim());
|
|
217
|
+
filePaths.forEach(p => paths.add(p));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Pattern 3: **Files to modify**: path1, path2
|
|
221
|
+
const modifyMatch = description.match(/\*\*Files to modify\*\*:\s*([^\n]+)/i);
|
|
222
|
+
if (modifyMatch) {
|
|
223
|
+
const filePaths = modifyMatch[1].split(',').map(p => p.trim());
|
|
224
|
+
filePaths.forEach(p => paths.add(p));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Pattern 4: Inline file references (e.g., `src/foo/bar.ts`)
|
|
228
|
+
const inlineMatches = description.matchAll(/`([a-zA-Z0-9_\-./]+\.(ts|js|tsx|jsx|py|java|go|rs|cpp|c|h))`/g);
|
|
229
|
+
for (const match of inlineMatches) {
|
|
230
|
+
paths.add(match[1]);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Pattern 5: Markdown list items with file paths
|
|
234
|
+
const listMatches = description.matchAll(/^[-*]\s+([a-zA-Z0-9_\-./]+\.(ts|js|tsx|jsx|py|java|go|rs|cpp|c|h))/gm);
|
|
235
|
+
for (const match of listMatches) {
|
|
236
|
+
paths.add(match[1]);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return Array.from(paths);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Batch validate multiple tasks
|
|
244
|
+
*
|
|
245
|
+
* @param tasks - Array of {taskId, description}
|
|
246
|
+
* @returns Array of validation results
|
|
247
|
+
*/
|
|
248
|
+
async validateTasks(tasks: Array<{ taskId: string; description: string }>): Promise<TaskValidationResult[]> {
|
|
249
|
+
// Use parallel validation for performance
|
|
250
|
+
const validationPromises = tasks.map(task =>
|
|
251
|
+
this.validateTask(task.description, task.taskId)
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
return Promise.all(validationPromises);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Get summary of validation results
|
|
259
|
+
*
|
|
260
|
+
* @param results - Array of task validation results
|
|
261
|
+
* @returns Summary statistics
|
|
262
|
+
*/
|
|
263
|
+
summarizeResults(results: TaskValidationResult[]): {
|
|
264
|
+
total: number;
|
|
265
|
+
valid: number;
|
|
266
|
+
invalid: number;
|
|
267
|
+
noFiles: number;
|
|
268
|
+
invalidTasks: string[];
|
|
269
|
+
} {
|
|
270
|
+
const total = results.length;
|
|
271
|
+
const valid = results.filter(r => r.valid).length;
|
|
272
|
+
const invalid = results.filter(r => !r.valid).length;
|
|
273
|
+
const noFiles = results.filter(r => r.files.length === 0).length;
|
|
274
|
+
const invalidTasks = results.filter(r => !r.valid).map(r => r.taskId);
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
total,
|
|
278
|
+
valid,
|
|
279
|
+
invalid,
|
|
280
|
+
noFiles,
|
|
281
|
+
invalidTasks
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|