specweave 0.22.0 → 0.22.3
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 +373 -13
- package/README.md +5 -5
- package/bin/specweave.js +5 -8
- package/dist/plugins/specweave-github/lib/CodeValidator.d.ts +1 -1
- package/dist/plugins/specweave-github/lib/CodeValidator.js +1 -1
- 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/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/repair-status-desync.d.ts +69 -0
- package/dist/src/cli/commands/repair-status-desync.d.ts.map +1 -0
- package/dist/src/cli/commands/repair-status-desync.js +221 -0
- package/dist/src/cli/commands/repair-status-desync.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/commands/validate-status-sync.d.ts +52 -0
- package/dist/src/cli/commands/validate-status-sync.d.ts.map +1 -0
- package/dist/src/cli/commands/validate-status-sync.js +176 -0
- package/dist/src/cli/commands/validate-status-sync.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/cli/update-status-line.d.ts +16 -0
- package/dist/src/cli/update-status-line.d.ts.map +1 -0
- package/dist/src/cli/update-status-line.js +44 -0
- package/dist/src/cli/update-status-line.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 +50 -50
- 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/completion-validator.d.ts +56 -0
- package/dist/src/core/increment/completion-validator.d.ts.map +1 -0
- package/dist/src/core/increment/completion-validator.js +102 -0
- package/dist/src/core/increment/completion-validator.js.map +1 -0
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +10 -0
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/increment/spec-frontmatter-updater.d.ts +78 -0
- package/dist/src/core/increment/spec-frontmatter-updater.d.ts.map +1 -0
- package/dist/src/core/increment/spec-frontmatter-updater.js +152 -0
- package/dist/src/core/increment/spec-frontmatter-updater.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/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 +727 -0
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -0
- 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 +7 -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 +47 -18
- package/dist/src/core/status-line/status-line-manager.js.map +1 -1
- package/dist/src/core/status-line/status-line-updater.d.ts +67 -0
- package/dist/src/core/status-line/status-line-updater.d.ts.map +1 -0
- package/dist/src/core/status-line/status-line-updater.js +203 -0
- package/dist/src/core/status-line/status-line-updater.js.map +1 -0
- 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/status-line/types.d.ts +19 -5
- package/dist/src/core/status-line/types.d.ts.map +1 -1
- package/dist/src/core/status-line/types.js +3 -3
- package/dist/src/core/status-line/types.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/architecture/types.d.ts +10 -10
- 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 +4 -4
- 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 +72 -4
- 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 +30 -3
- package/plugins/specweave/commands/specweave-restore-feature.md +1 -1
- package/plugins/specweave/commands/specweave-sync-docs.md +71 -4
- package/plugins/specweave/commands/specweave-sync-specs.md +20 -48
- package/plugins/specweave/commands/specweave-update-status.md +151 -0
- package/plugins/specweave/hooks/lib/update-status-line.sh +78 -41
- package/plugins/specweave/hooks/lib/validate-spec-status.sh +163 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +38 -35
- package/plugins/specweave/hooks/validate-increment-completion.sh +113 -0
- 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/ado-multi-project-sync.js +0 -1
- package/plugins/specweave-github/agents/github-manager/AGENT.md +39 -7
- package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +21 -0
- package/plugins/specweave-github/commands/specweave-github-create-issue.md +5 -5
- package/plugins/specweave-github/lib/CodeValidator.ts +1 -1
- 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/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
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -1200
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Pre-commit hook: Validate Increment Completion
|
|
4
|
+
#
|
|
5
|
+
# Prevents commits where increment status="completed" but:
|
|
6
|
+
# - Acceptance criteria are still open (- [ ] **AC-...)
|
|
7
|
+
# - Tasks are still pending (**Status**: [ ] pending)
|
|
8
|
+
#
|
|
9
|
+
# This prevents false completion and data integrity violations.
|
|
10
|
+
#
|
|
11
|
+
# Exit code 0: All completed increments are valid (allow commit)
|
|
12
|
+
# Exit code 1: Invalid completion detected (block commit)
|
|
13
|
+
|
|
14
|
+
# ANSI colors
|
|
15
|
+
RED='\033[0;31m'
|
|
16
|
+
YELLOW='\033[1;33m'
|
|
17
|
+
GREEN='\033[0;32m'
|
|
18
|
+
NC='\033[0m' # No Color
|
|
19
|
+
|
|
20
|
+
# Check if in SpecWeave project
|
|
21
|
+
if [ ! -d ".specweave/increments" ]; then
|
|
22
|
+
# Not a SpecWeave project, skip validation
|
|
23
|
+
exit 0
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Track if any validation failures found
|
|
27
|
+
has_failures=false
|
|
28
|
+
|
|
29
|
+
# Check all increments
|
|
30
|
+
for increment_dir in .specweave/increments/*/; do
|
|
31
|
+
# Skip if not a directory
|
|
32
|
+
[ ! -d "$increment_dir" ] && continue
|
|
33
|
+
|
|
34
|
+
increment_id=$(basename "$increment_dir")
|
|
35
|
+
spec_file="$increment_dir/spec.md"
|
|
36
|
+
tasks_file="$increment_dir/tasks.md"
|
|
37
|
+
metadata_file="$increment_dir/metadata.json"
|
|
38
|
+
|
|
39
|
+
# Skip if required files don't exist
|
|
40
|
+
[ ! -f "$spec_file" ] && continue
|
|
41
|
+
[ ! -f "$tasks_file" ] && continue
|
|
42
|
+
|
|
43
|
+
# Get status from spec.md frontmatter
|
|
44
|
+
spec_status=$(grep -m1 "^status:" "$spec_file" 2>/dev/null | cut -d: -f2 | tr -d ' ')
|
|
45
|
+
|
|
46
|
+
# Get status from metadata.json (if exists)
|
|
47
|
+
metadata_status=""
|
|
48
|
+
if [ -f "$metadata_file" ]; then
|
|
49
|
+
metadata_status=$(grep -m1 '"status"' "$metadata_file" 2>/dev/null | cut -d'"' -f4)
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Only validate if status is "completed"
|
|
53
|
+
if [ "$spec_status" = "completed" ] || [ "$metadata_status" = "completed" ]; then
|
|
54
|
+
# Count open acceptance criteria (- [ ] **AC-)
|
|
55
|
+
open_acs=$(grep -c "^- \[ \] \*\*AC-" "$spec_file" 2>/dev/null || echo 0)
|
|
56
|
+
|
|
57
|
+
# Count pending tasks (**Status**: [ ] pending)
|
|
58
|
+
pending_tasks=$(grep -ic "\*\*Status\*\*:\s*\[\s*\]\s*pending" "$tasks_file" 2>/dev/null || echo 0)
|
|
59
|
+
|
|
60
|
+
# Validate
|
|
61
|
+
if [ "$open_acs" -gt 0 ] || [ "$pending_tasks" -gt 0 ]; then
|
|
62
|
+
has_failures=true
|
|
63
|
+
|
|
64
|
+
echo -e "${RED}❌ COMMIT BLOCKED: Invalid completion detected${NC}"
|
|
65
|
+
echo -e "${YELLOW}Increment: $increment_id${NC}"
|
|
66
|
+
echo -e "Status: $spec_status (spec.md) / $metadata_status (metadata.json)"
|
|
67
|
+
echo ""
|
|
68
|
+
|
|
69
|
+
if [ "$open_acs" -gt 0 ]; then
|
|
70
|
+
echo -e "${RED} • $open_acs acceptance criteria still open${NC}"
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
if [ "$pending_tasks" -gt 0 ]; then
|
|
74
|
+
echo -e "${RED} • $pending_tasks tasks still pending${NC}"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
echo ""
|
|
78
|
+
echo -e "${YELLOW}Fix options:${NC}"
|
|
79
|
+
echo " 1. Complete the open work before committing"
|
|
80
|
+
echo " 2. Change status to 'active' or 'paused' in both spec.md and metadata.json"
|
|
81
|
+
echo ""
|
|
82
|
+
echo -e "${YELLOW}To see details:${NC}"
|
|
83
|
+
echo " cat $spec_file | grep '- \[ \] \*\*AC-'"
|
|
84
|
+
echo " cat $tasks_file | grep -i 'Status.*pending'"
|
|
85
|
+
echo ""
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
done
|
|
89
|
+
|
|
90
|
+
# Exit with failure if any validation failures
|
|
91
|
+
if [ "$has_failures" = true ]; then
|
|
92
|
+
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
93
|
+
echo -e "${RED}COMMIT BLOCKED: Cannot commit increments with invalid completion${NC}"
|
|
94
|
+
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
95
|
+
echo ""
|
|
96
|
+
echo -e "${YELLOW}Why this matters:${NC}"
|
|
97
|
+
echo " • Prevents false completion (status='completed' with open work)"
|
|
98
|
+
echo " • Ensures data integrity (metadata matches reality)"
|
|
99
|
+
echo " • Stops misleading status line and GitHub sync"
|
|
100
|
+
echo ""
|
|
101
|
+
echo -e "${YELLOW}To fix:${NC}"
|
|
102
|
+
echo " 1. Complete all open ACs and pending tasks, OR"
|
|
103
|
+
echo " 2. Change status to 'active'/'paused' in spec.md and metadata.json"
|
|
104
|
+
echo ""
|
|
105
|
+
echo -e "${YELLOW}To bypass (NOT RECOMMENDED):${NC}"
|
|
106
|
+
echo " git commit --no-verify"
|
|
107
|
+
echo ""
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# All validations passed
|
|
112
|
+
echo -e "${GREEN}✅ Completion validation passed${NC}"
|
|
113
|
+
exit 0
|
|
@@ -20,13 +20,22 @@ async function updateTasksMd(incrementId) {
|
|
|
20
20
|
console.log(`\u{1F4D6} Read tasks.md (${lines.length} lines)`);
|
|
21
21
|
const tasks = parseTaskStatus(lines);
|
|
22
22
|
console.log(`\u{1F4CB} Found ${tasks.length} tasks`);
|
|
23
|
-
const completedTasks = detectCompletedTasks(lines);
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const { completedTasks, fixes } = detectCompletedTasks(lines);
|
|
24
|
+
let updatedContent = originalContent;
|
|
25
|
+
let autoFixedCount = 0;
|
|
26
|
+
if (fixes.length > 0) {
|
|
27
|
+
console.log(`\u{1F527} Auto-fixing ${fixes.length} task consistency issue(s)...`);
|
|
28
|
+
updatedContent = applyConsistencyFixes(originalContent, fixes);
|
|
29
|
+
autoFixedCount = fixes.length;
|
|
30
|
+
console.log("\u2705 Task consistency auto-fixed");
|
|
31
|
+
}
|
|
32
|
+
if (completedTasks.length === 0 && fixes.length === 0) {
|
|
33
|
+
console.log("\u2705 No new task completions or consistency fixes needed");
|
|
26
34
|
return;
|
|
27
35
|
}
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
if (completedTasks.length > 0) {
|
|
37
|
+
console.log(`\u{1F3AF} Detected ${completedTasks.length} completed task(s):`, completedTasks);
|
|
38
|
+
}
|
|
30
39
|
for (const taskId of completedTasks) {
|
|
31
40
|
updatedContent = markTaskComplete(updatedContent, taskId);
|
|
32
41
|
}
|
|
@@ -38,6 +47,9 @@ async function updateTasksMd(incrementId) {
|
|
|
38
47
|
updatedContent = updateProgressHeader(updatedContent, completedCount, totalTasks, progress);
|
|
39
48
|
await fs.writeFile(tasksPath, updatedContent, "utf-8");
|
|
40
49
|
console.log(`\u2705 Updated ${tasksPath}`);
|
|
50
|
+
if (autoFixedCount > 0) {
|
|
51
|
+
console.log(`\u{1F527} Auto-fixed ${autoFixedCount} consistency issue(s)`);
|
|
52
|
+
}
|
|
41
53
|
console.log(` Completed: ${completedCount}/${totalTasks}`);
|
|
42
54
|
console.log(` Progress: ${progress}%
|
|
43
55
|
`);
|
|
@@ -78,6 +90,7 @@ function parseTaskStatus(lines) {
|
|
|
78
90
|
}
|
|
79
91
|
function detectCompletedTasks(lines) {
|
|
80
92
|
const completedTasks = [];
|
|
93
|
+
const fixes = [];
|
|
81
94
|
const warnings = [];
|
|
82
95
|
const taskPattern = /^###\s+(T-\d+[-A-Z]*):?\s+(.+)/;
|
|
83
96
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -99,17 +112,33 @@ function detectCompletedTasks(lines) {
|
|
|
99
112
|
completedTasks.push(taskId);
|
|
100
113
|
}
|
|
101
114
|
} else {
|
|
115
|
+
fixes.push({
|
|
116
|
+
taskId,
|
|
117
|
+
lineNumber: i,
|
|
118
|
+
action: "remove-complete-marker",
|
|
119
|
+
currentLine: line
|
|
120
|
+
});
|
|
102
121
|
warnings.push(`${taskId}: Header has \u2705 COMPLETE but not all checkboxes checked`);
|
|
103
122
|
}
|
|
104
123
|
continue;
|
|
105
124
|
}
|
|
106
125
|
if (hasCompleteMarker && !implementationSection) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
126
|
+
fixes.push({
|
|
127
|
+
taskId,
|
|
128
|
+
lineNumber: i,
|
|
129
|
+
action: "remove-complete-marker",
|
|
130
|
+
currentLine: line
|
|
131
|
+
});
|
|
132
|
+
warnings.push(`${taskId}: Header has \u2705 COMPLETE but no implementation section to verify`);
|
|
110
133
|
continue;
|
|
111
134
|
}
|
|
112
135
|
if (!hasCompleteMarker && implementationSection && allCheckboxesComplete) {
|
|
136
|
+
fixes.push({
|
|
137
|
+
taskId,
|
|
138
|
+
lineNumber: i,
|
|
139
|
+
action: "add-complete-marker",
|
|
140
|
+
currentLine: line
|
|
141
|
+
});
|
|
113
142
|
warnings.push(`${taskId}: All checkboxes checked but header missing \u2705 COMPLETE`);
|
|
114
143
|
if (!completedTasks.includes(taskId)) {
|
|
115
144
|
completedTasks.push(taskId);
|
|
@@ -131,7 +160,21 @@ function detectCompletedTasks(lines) {
|
|
|
131
160
|
warnings.forEach((w) => console.warn(` ${w}`));
|
|
132
161
|
console.warn("");
|
|
133
162
|
}
|
|
134
|
-
return completedTasks;
|
|
163
|
+
return { completedTasks, fixes };
|
|
164
|
+
}
|
|
165
|
+
function applyConsistencyFixes(content, fixes) {
|
|
166
|
+
const lines = content.split("\n");
|
|
167
|
+
for (const fix of fixes.reverse()) {
|
|
168
|
+
const line = lines[fix.lineNumber];
|
|
169
|
+
if (fix.action === "remove-complete-marker") {
|
|
170
|
+
const fixed = line.replace(/\s*✅\s*COMPLETE\s*/g, "");
|
|
171
|
+
lines[fix.lineNumber] = fixed;
|
|
172
|
+
} else if (fix.action === "add-complete-marker") {
|
|
173
|
+
const fixed = line.trim() + " \u2705 COMPLETE";
|
|
174
|
+
lines[fix.lineNumber] = fixed;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return lines.join("\n");
|
|
135
178
|
}
|
|
136
179
|
function findNextTaskStart(lines, startIndex) {
|
|
137
180
|
const taskPattern = /^###\s+T-\d+/;
|
|
@@ -32,6 +32,13 @@ interface TaskMatch {
|
|
|
32
32
|
currentStatus: 'pending' | 'in_progress' | 'completed';
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
interface TaskConsistencyFix {
|
|
36
|
+
taskId: string;
|
|
37
|
+
lineNumber: number;
|
|
38
|
+
action: 'add-complete-marker' | 'remove-complete-marker';
|
|
39
|
+
currentLine: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
35
42
|
/**
|
|
36
43
|
* Main function - update tasks.md for given increment
|
|
37
44
|
*/
|
|
@@ -62,20 +69,30 @@ async function updateTasksMd(incrementId: string): Promise<void> {
|
|
|
62
69
|
const tasks = parseTaskStatus(lines);
|
|
63
70
|
console.log(`📋 Found ${tasks.length} tasks`);
|
|
64
71
|
|
|
65
|
-
// 4. Get recently completed tasks
|
|
66
|
-
|
|
67
|
-
// TODO: In future, hook will pass completed task IDs via env var
|
|
68
|
-
const completedTasks = detectCompletedTasks(lines);
|
|
72
|
+
// 4. Get recently completed tasks and consistency fixes
|
|
73
|
+
const { completedTasks, fixes } = detectCompletedTasks(lines);
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
// 4a. Apply consistency fixes FIRST (if any)
|
|
76
|
+
let updatedContent = originalContent;
|
|
77
|
+
let autoFixedCount = 0;
|
|
78
|
+
|
|
79
|
+
if (fixes.length > 0) {
|
|
80
|
+
console.log(`🔧 Auto-fixing ${fixes.length} task consistency issue(s)...`);
|
|
81
|
+
updatedContent = applyConsistencyFixes(originalContent, fixes);
|
|
82
|
+
autoFixedCount = fixes.length;
|
|
83
|
+
console.log('✅ Task consistency auto-fixed');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (completedTasks.length === 0 && fixes.length === 0) {
|
|
87
|
+
console.log('✅ No new task completions or consistency fixes needed');
|
|
72
88
|
return;
|
|
73
89
|
}
|
|
74
90
|
|
|
75
|
-
|
|
91
|
+
if (completedTasks.length > 0) {
|
|
92
|
+
console.log(`🎯 Detected ${completedTasks.length} completed task(s):`, completedTasks);
|
|
93
|
+
}
|
|
76
94
|
|
|
77
95
|
// 5. Update task status in content
|
|
78
|
-
let updatedContent = originalContent;
|
|
79
96
|
|
|
80
97
|
for (const taskId of completedTasks) {
|
|
81
98
|
updatedContent = markTaskComplete(updatedContent, taskId);
|
|
@@ -96,6 +113,9 @@ async function updateTasksMd(incrementId: string): Promise<void> {
|
|
|
96
113
|
await fs.writeFile(tasksPath, updatedContent, 'utf-8');
|
|
97
114
|
|
|
98
115
|
console.log(`✅ Updated ${tasksPath}`);
|
|
116
|
+
if (autoFixedCount > 0) {
|
|
117
|
+
console.log(`🔧 Auto-fixed ${autoFixedCount} consistency issue(s)`);
|
|
118
|
+
}
|
|
99
119
|
console.log(` Completed: ${completedCount}/${totalTasks}`);
|
|
100
120
|
console.log(` Progress: ${progress}%\n`);
|
|
101
121
|
|
|
@@ -158,8 +178,9 @@ function parseTaskStatus(lines: string[]): TaskMatch[] {
|
|
|
158
178
|
*
|
|
159
179
|
* @see .specweave/increments/0037/reports/ULTRATHINK-COMPLETE-MARKER-VS-CHECKBOXES.md
|
|
160
180
|
*/
|
|
161
|
-
function detectCompletedTasks(lines: string[]): string[] {
|
|
181
|
+
function detectCompletedTasks(lines: string[]): { completedTasks: string[]; fixes: TaskConsistencyFix[] } {
|
|
162
182
|
const completedTasks: string[] = [];
|
|
183
|
+
const fixes: TaskConsistencyFix[] = [];
|
|
163
184
|
const warnings: string[] = [];
|
|
164
185
|
const taskPattern = /^###\s+(T-\d+[-A-Z]*):?\s+(.+)/;
|
|
165
186
|
|
|
@@ -190,22 +211,38 @@ function detectCompletedTasks(lines: string[]): string[] {
|
|
|
190
211
|
completedTasks.push(taskId);
|
|
191
212
|
}
|
|
192
213
|
} else {
|
|
193
|
-
// ⚠️ INCONSISTENT: Header says COMPLETE but checkboxes incomplete
|
|
214
|
+
// ⚠️ INCONSISTENT: Header says COMPLETE but checkboxes incomplete - AUTO-FIX
|
|
215
|
+
fixes.push({
|
|
216
|
+
taskId,
|
|
217
|
+
lineNumber: i,
|
|
218
|
+
action: 'remove-complete-marker',
|
|
219
|
+
currentLine: line
|
|
220
|
+
});
|
|
194
221
|
warnings.push(`${taskId}: Header has ✅ COMPLETE but not all checkboxes checked`);
|
|
195
222
|
}
|
|
196
223
|
continue;
|
|
197
224
|
}
|
|
198
225
|
|
|
199
|
-
// If no implementation section,
|
|
226
|
+
// If no implementation section, remove COMPLETE marker (can't verify)
|
|
200
227
|
if (hasCompleteMarker && !implementationSection) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
228
|
+
fixes.push({
|
|
229
|
+
taskId,
|
|
230
|
+
lineNumber: i,
|
|
231
|
+
action: 'remove-complete-marker',
|
|
232
|
+
currentLine: line
|
|
233
|
+
});
|
|
234
|
+
warnings.push(`${taskId}: Header has ✅ COMPLETE but no implementation section to verify`);
|
|
204
235
|
continue;
|
|
205
236
|
}
|
|
206
237
|
|
|
207
|
-
// Warn if checkboxes all complete but header missing marker
|
|
238
|
+
// Warn if checkboxes all complete but header missing marker - AUTO-FIX
|
|
208
239
|
if (!hasCompleteMarker && implementationSection && allCheckboxesComplete) {
|
|
240
|
+
fixes.push({
|
|
241
|
+
taskId,
|
|
242
|
+
lineNumber: i,
|
|
243
|
+
action: 'add-complete-marker',
|
|
244
|
+
currentLine: line
|
|
245
|
+
});
|
|
209
246
|
warnings.push(`${taskId}: All checkboxes checked but header missing ✅ COMPLETE`);
|
|
210
247
|
// Still count as complete (checkboxes are source of truth for work done)
|
|
211
248
|
if (!completedTasks.includes(taskId)) {
|
|
@@ -233,7 +270,31 @@ function detectCompletedTasks(lines: string[]): string[] {
|
|
|
233
270
|
console.warn('');
|
|
234
271
|
}
|
|
235
272
|
|
|
236
|
-
return completedTasks;
|
|
273
|
+
return { completedTasks, fixes };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Apply task consistency fixes to content
|
|
278
|
+
*/
|
|
279
|
+
function applyConsistencyFixes(content: string, fixes: TaskConsistencyFix[]): string {
|
|
280
|
+
const lines = content.split('\n');
|
|
281
|
+
|
|
282
|
+
// Apply fixes (process in reverse order to preserve line numbers)
|
|
283
|
+
for (const fix of fixes.reverse()) {
|
|
284
|
+
const line = lines[fix.lineNumber];
|
|
285
|
+
|
|
286
|
+
if (fix.action === 'remove-complete-marker') {
|
|
287
|
+
// Remove ✅ COMPLETE from header
|
|
288
|
+
const fixed = line.replace(/\s*✅\s*COMPLETE\s*/g, '');
|
|
289
|
+
lines[fix.lineNumber] = fixed;
|
|
290
|
+
} else if (fix.action === 'add-complete-marker') {
|
|
291
|
+
// Add ✅ COMPLETE to header (before any trailing spaces)
|
|
292
|
+
const fixed = line.trim() + ' ✅ COMPLETE';
|
|
293
|
+
lines[fix.lineNumber] = fixed;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return lines.join('\n');
|
|
237
298
|
}
|
|
238
299
|
|
|
239
300
|
/**
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"region": "us-east-1",
|
|
3
|
+
"functionName": "my-lambda-function",
|
|
4
|
+
"runtime": "nodejs20.x",
|
|
5
|
+
"handler": "index.handler",
|
|
6
|
+
"memorySize": 128,
|
|
7
|
+
"timeout": 30,
|
|
8
|
+
"environment": "dev",
|
|
9
|
+
"databaseName": "my-dynamodb-table",
|
|
10
|
+
"primaryKey": "id",
|
|
11
|
+
"apiName": "my-api",
|
|
12
|
+
"apiStageName": "default",
|
|
13
|
+
"logRetentionDays": 90,
|
|
14
|
+
"corsOrigins": ["*"],
|
|
15
|
+
"projectName": "my-project",
|
|
16
|
+
"enableVpc": false,
|
|
17
|
+
"enableXray": false,
|
|
18
|
+
"enableSecretsManager": false,
|
|
19
|
+
"enableKms": false,
|
|
20
|
+
"enableEncryption": false,
|
|
21
|
+
"enablePointInTimeRecovery": false,
|
|
22
|
+
"enableStreams": false,
|
|
23
|
+
"enableRemoteState": false
|
|
24
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# {{functionName}} - AWS Lambda Serverless Infrastructure
|
|
2
|
+
|
|
3
|
+
**Generated by SpecWeave Serverless Architecture Intelligence**
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This Terraform configuration deploys a complete serverless application stack on AWS:
|
|
8
|
+
|
|
9
|
+
- **Lambda Function**: `{{functionName}}` ({{runtime}}, {{memorySize}}MB memory, {{timeout}}s timeout)
|
|
10
|
+
- **API Gateway**: HTTP API with CORS support
|
|
11
|
+
- **DynamoDB**: NoSQL database table `{{databaseName}}`
|
|
12
|
+
- **CloudWatch Logs**: Centralized logging with {{logRetentionDays}}-day retention
|
|
13
|
+
{{#if enableVpc}}- **VPC Integration**: Secure network isolation{{/if}}
|
|
14
|
+
{{#if enableXray}}- **X-Ray Tracing**: Distributed tracing enabled{{/if}}
|
|
15
|
+
{{#if enableSecretsManager}}- **Secrets Manager**: Secure secret storage{{/if}}
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
┌─────────────┐
|
|
21
|
+
│ Client │
|
|
22
|
+
└──────┬──────┘
|
|
23
|
+
│ HTTPS
|
|
24
|
+
v
|
|
25
|
+
┌─────────────────┐
|
|
26
|
+
│ API Gateway │
|
|
27
|
+
│ (HTTP API) │
|
|
28
|
+
└──────┬──────────┘
|
|
29
|
+
│
|
|
30
|
+
v
|
|
31
|
+
┌────────────────────┐ ┌──────────────┐
|
|
32
|
+
│ Lambda Function │─────>│ DynamoDB │
|
|
33
|
+
│ {{functionName}} │ │ {{databaseName}} │
|
|
34
|
+
└────────────────────┘ └──────────────┘
|
|
35
|
+
│
|
|
36
|
+
v
|
|
37
|
+
┌────────────────────┐
|
|
38
|
+
│ CloudWatch Logs │
|
|
39
|
+
└────────────────────┘
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Prerequisites
|
|
43
|
+
|
|
44
|
+
1. **AWS CLI** configured with credentials:
|
|
45
|
+
```bash
|
|
46
|
+
aws configure
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
2. **Terraform** v1.5.0 or higher:
|
|
50
|
+
```bash
|
|
51
|
+
terraform version
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
3. **Lambda deployment package** ({{functionName}}.zip):
|
|
55
|
+
- Create your Lambda function code
|
|
56
|
+
- Package as {{functionName}}.zip
|
|
57
|
+
- Place in the same directory as this README
|
|
58
|
+
|
|
59
|
+
## Deployment Instructions
|
|
60
|
+
|
|
61
|
+
### Step 1: Initialize Terraform
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
terraform init
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This downloads the AWS provider and initializes the backend.
|
|
68
|
+
|
|
69
|
+
### Step 2: Review Configuration
|
|
70
|
+
|
|
71
|
+
Edit `terraform.tfvars` (or create environment-specific files like `dev.tfvars`) to customize:
|
|
72
|
+
|
|
73
|
+
```hcl
|
|
74
|
+
aws_region = "{{region}}"
|
|
75
|
+
function_name = "{{functionName}}"
|
|
76
|
+
environment = "{{environment}}"
|
|
77
|
+
runtime = "{{runtime}}"
|
|
78
|
+
memory_size = {{memorySize}}
|
|
79
|
+
timeout = {{timeout}}
|
|
80
|
+
database_name = "{{databaseName}}"
|
|
81
|
+
primary_key = "{{primaryKey}}"
|
|
82
|
+
project_name = "{{projectName}}"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Step 3: Plan Deployment
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
terraform plan
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Review the resources that will be created:
|
|
92
|
+
- 1× Lambda Function
|
|
93
|
+
- 1× API Gateway HTTP API
|
|
94
|
+
- 1× DynamoDB Table
|
|
95
|
+
- 2× CloudWatch Log Groups
|
|
96
|
+
- 1× IAM Role + Policies
|
|
97
|
+
{{#if enableVpc}}- 1× Security Group (VPC){{/if}}
|
|
98
|
+
|
|
99
|
+
### Step 4: Deploy
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
terraform apply
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Type `yes` when prompted to confirm deployment.
|
|
106
|
+
|
|
107
|
+
### Step 5: Verify Deployment
|
|
108
|
+
|
|
109
|
+
After successful deployment, Terraform will output:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
api_endpoint = "https://xxxxxxxxxx.execute-api.{{region}}.amazonaws.com/{{apiStageName}}"
|
|
113
|
+
function_name = "{{functionName}}"
|
|
114
|
+
table_name = "{{databaseName}}"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Test your API:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
curl https://xxxxxxxxxx.execute-api.{{region}}.amazonaws.com/{{apiStageName}}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Environment-Specific Deployments
|
|
124
|
+
|
|
125
|
+
Deploy to different environments using tfvars files:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Development
|
|
129
|
+
terraform apply -var-file="environments/dev.tfvars"
|
|
130
|
+
|
|
131
|
+
# Staging
|
|
132
|
+
terraform apply -var-file="environments/staging.tfvars"
|
|
133
|
+
|
|
134
|
+
# Production
|
|
135
|
+
terraform apply -var-file="environments/prod.tfvars"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Cost Optimization
|
|
139
|
+
|
|
140
|
+
### Free Tier Limits (First 12 Months)
|
|
141
|
+
|
|
142
|
+
- **Lambda**: 1M requests/month + 400,000 GB-seconds compute
|
|
143
|
+
- **API Gateway**: 1M API calls/month (first 12 months)
|
|
144
|
+
- **DynamoDB**: 25GB storage + 25 WCU + 25 RCU (always free)
|
|
145
|
+
- **CloudWatch Logs**: 5GB ingestion + 5GB storage
|
|
146
|
+
|
|
147
|
+
### Estimated Monthly Cost (After Free Tier)
|
|
148
|
+
|
|
149
|
+
**{{environment}} Environment**:
|
|
150
|
+
{{#if eq environment "dev"}}
|
|
151
|
+
- **Lambda**: ~$0.20/month (10K requests, 128MB, 1s avg duration)
|
|
152
|
+
- **API Gateway**: ~$0.10/month (10K requests)
|
|
153
|
+
- **DynamoDB**: $0.00/month (PAY_PER_REQUEST under free tier)
|
|
154
|
+
- **CloudWatch Logs**: ~$0.50/month (1GB logs)
|
|
155
|
+
- **Total**: ~$0.80/month
|
|
156
|
+
{{else}}{{#if eq environment "staging"}}
|
|
157
|
+
- **Lambda**: ~$2.00/month (100K requests, 256MB, 1s avg duration)
|
|
158
|
+
- **API Gateway**: ~$1.00/month (100K requests)
|
|
159
|
+
- **DynamoDB**: ~$1.25/month (PAY_PER_REQUEST, light usage)
|
|
160
|
+
- **CloudWatch Logs**: ~$1.00/month (2GB logs)
|
|
161
|
+
- **Total**: ~$5.25/month
|
|
162
|
+
{{else}}
|
|
163
|
+
- **Lambda**: ~$20.00/month (1M requests, 512MB, 1s avg duration)
|
|
164
|
+
- **API Gateway**: ~$10.00/month (1M requests)
|
|
165
|
+
- **DynamoDB**: ~$12.50/month (PROVISIONED, 5 RCU/WCU)
|
|
166
|
+
- **CloudWatch Logs**: ~$5.00/month (10GB logs)
|
|
167
|
+
- **Total**: ~$47.50/month
|
|
168
|
+
{{/if}}{{/if}}
|
|
169
|
+
|
|
170
|
+
### Cost Optimization Tips
|
|
171
|
+
|
|
172
|
+
1. **Right-size memory**: Test with different memory settings (128MB, 256MB, 512MB)
|
|
173
|
+
2. **Optimize timeout**: Reduce timeout to actual function duration
|
|
174
|
+
3. **Use PAY_PER_REQUEST**: For low-traffic apps (<100K requests/month)
|
|
175
|
+
4. **Enable CloudWatch Logs retention**: Delete old logs automatically
|
|
176
|
+
5. **Monitor cold starts**: Use Provisioned Concurrency if needed ($$)
|
|
177
|
+
|
|
178
|
+
## Security Best Practices
|
|
179
|
+
|
|
180
|
+
✅ **Implemented**:
|
|
181
|
+
- IAM least privilege roles
|
|
182
|
+
- HTTPS-only API Gateway
|
|
183
|
+
- CloudWatch Logs encryption
|
|
184
|
+
- DynamoDB encryption at rest (if enabled)
|
|
185
|
+
- Secrets Manager for sensitive data (if enabled)
|
|
186
|
+
|
|
187
|
+
⚠️ **Additional Recommendations**:
|
|
188
|
+
- Enable AWS WAF for API Gateway
|
|
189
|
+
- Implement rate limiting
|
|
190
|
+
- Use AWS Shield for DDoS protection
|
|
191
|
+
- Enable VPC for database access
|
|
192
|
+
- Rotate secrets regularly
|
|
193
|
+
|
|
194
|
+
## Monitoring and Logging
|
|
195
|
+
|
|
196
|
+
### CloudWatch Logs
|
|
197
|
+
|
|
198
|
+
View Lambda logs:
|
|
199
|
+
```bash
|
|
200
|
+
aws logs tail /aws/lambda/{{functionName}} --follow
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
View API Gateway logs:
|
|
204
|
+
```bash
|
|
205
|
+
aws logs tail /aws/apigateway/{{apiName}}-{{environment}} --follow
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### CloudWatch Metrics
|
|
209
|
+
|
|
210
|
+
Monitor in AWS Console:
|
|
211
|
+
- Lambda: Invocations, Duration, Errors, Throttles
|
|
212
|
+
- API Gateway: Count, Latency, 4XX/5XX errors
|
|
213
|
+
- DynamoDB: Read/Write capacity, Throttled requests
|
|
214
|
+
|
|
215
|
+
## Cleanup
|
|
216
|
+
|
|
217
|
+
To destroy all resources:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
terraform destroy
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Type `yes` to confirm deletion.
|
|
224
|
+
|
|
225
|
+
**Warning**: This will permanently delete:
|
|
226
|
+
- Lambda function
|
|
227
|
+
- API Gateway
|
|
228
|
+
- DynamoDB table (and all data)
|
|
229
|
+
- CloudWatch Logs
|
|
230
|
+
|
|
231
|
+
## Troubleshooting
|
|
232
|
+
|
|
233
|
+
### Lambda Function Not Working
|
|
234
|
+
|
|
235
|
+
1. Check CloudWatch Logs for errors
|
|
236
|
+
2. Verify IAM role permissions
|
|
237
|
+
3. Test function locally with AWS SAM
|
|
238
|
+
|
|
239
|
+
### API Gateway 403 Errors
|
|
240
|
+
|
|
241
|
+
1. Verify Lambda permission for API Gateway
|
|
242
|
+
2. Check CORS configuration
|
|
243
|
+
3. Review API Gateway execution logs
|
|
244
|
+
|
|
245
|
+
### DynamoDB Access Denied
|
|
246
|
+
|
|
247
|
+
1. Verify Lambda IAM role has DynamoDB permissions
|
|
248
|
+
2. Check table name matches environment variable
|
|
249
|
+
3. Verify primary key schema
|
|
250
|
+
|
|
251
|
+
## Support
|
|
252
|
+
|
|
253
|
+
For issues with this Terraform configuration, contact your SpecWeave administrator or file an issue at https://github.com/anton-abyzov/specweave/issues.
|
|
254
|
+
|
|
255
|
+
## Additional Resources
|
|
256
|
+
|
|
257
|
+
- [AWS Lambda Documentation](https://docs.aws.amazon.com/lambda/)
|
|
258
|
+
- [API Gateway HTTP API Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html)
|
|
259
|
+
- [DynamoDB Developer Guide](https://docs.aws.amazon.com/dynamodb/)
|
|
260
|
+
- [Terraform AWS Provider](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Development Environment Configuration
|
|
2
|
+
# Optimized for free tier and minimal costs
|
|
3
|
+
# Generated by SpecWeave Serverless Architecture Intelligence
|
|
4
|
+
|
|
5
|
+
aws_region = "{{region}}"
|
|
6
|
+
environment = "dev"
|
|
7
|
+
function_name = "{{functionName}}-dev"
|
|
8
|
+
runtime = "{{runtime}}"
|
|
9
|
+
|
|
10
|
+
# Free tier optimized settings
|
|
11
|
+
memory_size = 128 # Smallest memory size (free tier eligible)
|
|
12
|
+
timeout = 30 # Conservative timeout
|
|
13
|
+
|
|
14
|
+
# Database configuration
|
|
15
|
+
database_name = "{{databaseName}}-dev"
|
|
16
|
+
primary_key = "{{primaryKey}}"
|
|
17
|
+
{{#if sortKey}}
|
|
18
|
+
sort_key = "{{sortKey}}"
|
|
19
|
+
{{/if}}
|
|
20
|
+
|
|
21
|
+
# Logging (keep retention short in dev)
|
|
22
|
+
log_retention_days = 7
|
|
23
|
+
|
|
24
|
+
# CORS (allow localhost for development)
|
|
25
|
+
cors_origins = ["http://localhost:3000", "http://localhost:8080"]
|
|
26
|
+
|
|
27
|
+
# Project metadata
|
|
28
|
+
project_name = "{{projectName}}"
|
|
29
|
+
|
|
30
|
+
# Additional tags
|
|
31
|
+
tags = {
|
|
32
|
+
CostCenter = "Development"
|
|
33
|
+
AutoDelete = "true" # Mark for cleanup scripts
|
|
34
|
+
}
|