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
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# GCP Cloud Functions + Firestore Terraform Configuration
|
|
2
|
+
# Generated by SpecWeave Serverless Architecture Intelligence
|
|
3
|
+
|
|
4
|
+
# Enable required APIs
|
|
5
|
+
resource "google_project_service" "cloudfunctions" {
|
|
6
|
+
project = "{{projectId}}"
|
|
7
|
+
service = "cloudfunctions.googleapis.com"
|
|
8
|
+
|
|
9
|
+
disable_on_destroy = false
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
resource "google_project_service" "cloudbuild" {
|
|
13
|
+
project = "{{projectId}}"
|
|
14
|
+
service = "cloudbuild.googleapis.com"
|
|
15
|
+
|
|
16
|
+
disable_on_destroy = false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
resource "google_project_service" "firestore" {
|
|
20
|
+
project = "{{projectId}}"
|
|
21
|
+
service = "firestore.googleapis.com"
|
|
22
|
+
|
|
23
|
+
disable_on_destroy = false
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
resource "google_project_service" "run" {
|
|
27
|
+
project = "{{projectId}}"
|
|
28
|
+
service = "run.googleapis.com"
|
|
29
|
+
|
|
30
|
+
disable_on_destroy = false
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Service Account for Cloud Function
|
|
34
|
+
resource "google_service_account" "{{snakeCase serviceAccountId}}" {
|
|
35
|
+
account_id = "{{serviceAccountId}}"
|
|
36
|
+
display_name = "Service Account for {{functionName}}"
|
|
37
|
+
project = "{{projectId}}"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# IAM binding for Firestore access
|
|
41
|
+
resource "google_project_iam_member" "firestore_user" {
|
|
42
|
+
project = "{{projectId}}"
|
|
43
|
+
role = "roles/datastore.user"
|
|
44
|
+
member = "serviceAccount:${google_service_account.{{snakeCase serviceAccountId}}.email}"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Storage Bucket for function source code
|
|
48
|
+
resource "google_storage_bucket" "{{snakeCase bucketName}}" {
|
|
49
|
+
name = "{{bucketName}}-{{projectId}}"
|
|
50
|
+
location = "{{bucketLocation}}"
|
|
51
|
+
project = "{{projectId}}"
|
|
52
|
+
|
|
53
|
+
uniform_bucket_level_access = true
|
|
54
|
+
|
|
55
|
+
labels = {
|
|
56
|
+
environment = "{{environment}}"
|
|
57
|
+
managed_by = "terraform"
|
|
58
|
+
project = "{{projectName}}"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Storage Bucket Object for function source code (placeholder)
|
|
63
|
+
resource "google_storage_bucket_object" "function_source" {
|
|
64
|
+
name = "function-source-{{environment}}.zip"
|
|
65
|
+
bucket = google_storage_bucket.{{snakeCase bucketName}}.name
|
|
66
|
+
source = "function-source.zip" # You need to provide this file
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Cloud Function (2nd generation)
|
|
70
|
+
resource "google_cloudfunctions2_function" "{{snakeCase functionName}}" {
|
|
71
|
+
name = "{{functionName}}"
|
|
72
|
+
location = "{{region}}"
|
|
73
|
+
project = "{{projectId}}"
|
|
74
|
+
|
|
75
|
+
build_config {
|
|
76
|
+
runtime = "{{runtime}}"
|
|
77
|
+
entry_point = "{{entryPoint}}"
|
|
78
|
+
|
|
79
|
+
source {
|
|
80
|
+
storage_source {
|
|
81
|
+
bucket = google_storage_bucket.{{snakeCase bucketName}}.name
|
|
82
|
+
object = google_storage_bucket_object.function_source.name
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
service_config {
|
|
88
|
+
max_instance_count = {{maxInstances}}
|
|
89
|
+
min_instance_count = {{minInstances}}
|
|
90
|
+
available_memory = "{{memoryMb}}M"
|
|
91
|
+
timeout_seconds = {{timeoutSeconds}}
|
|
92
|
+
|
|
93
|
+
{{#if enableConcurrency}}
|
|
94
|
+
max_instance_request_concurrency = {{maxConcurrentRequests}}
|
|
95
|
+
{{/if}}
|
|
96
|
+
|
|
97
|
+
environment_variables = {
|
|
98
|
+
ENVIRONMENT = "{{environment}}"
|
|
99
|
+
GCP_PROJECT = "{{projectId}}"
|
|
100
|
+
FIRESTORE_DATABASE = "{{databaseId}}"
|
|
101
|
+
COLLECTION_ID = "{{collectionId}}"
|
|
102
|
+
{{#if customEnvVars}}
|
|
103
|
+
{{#each customEnvVars}}
|
|
104
|
+
{{@key}} = "{{this}}"
|
|
105
|
+
{{/each}}
|
|
106
|
+
{{/if}}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
service_account_email = google_service_account.{{snakeCase serviceAccountId}}.email
|
|
110
|
+
|
|
111
|
+
{{#if enableVpc}}
|
|
112
|
+
vpc_connector = google_vpc_access_connector.connector.id
|
|
113
|
+
vpc_connector_egress_settings = "ALL_TRAFFIC"
|
|
114
|
+
{{/if}}
|
|
115
|
+
|
|
116
|
+
{{#if corsOrigins}}
|
|
117
|
+
ingress_settings = "ALLOW_ALL"
|
|
118
|
+
{{/if}}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
labels = {
|
|
122
|
+
environment = "{{environment}}"
|
|
123
|
+
managed_by = "terraform"
|
|
124
|
+
project = "{{projectName}}"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
depends_on = [
|
|
128
|
+
google_project_service.cloudfunctions,
|
|
129
|
+
google_project_service.cloudbuild,
|
|
130
|
+
google_project_service.run,
|
|
131
|
+
google_project_iam_member.firestore_user
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Cloud Function IAM - Allow unauthenticated invocations (API Gateway equivalent)
|
|
136
|
+
resource "google_cloudfunctions2_function_iam_member" "invoker" {
|
|
137
|
+
project = google_cloudfunctions2_function.{{snakeCase functionName}}.project
|
|
138
|
+
location = google_cloudfunctions2_function.{{snakeCase functionName}}.location
|
|
139
|
+
cloud_function = google_cloudfunctions2_function.{{snakeCase functionName}}.name
|
|
140
|
+
|
|
141
|
+
role = "roles/cloudfunctions.invoker"
|
|
142
|
+
member = "allUsers" # For public API. Use specific members for private APIs
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
# Firestore Database
|
|
146
|
+
resource "google_firestore_database" "{{snakeCase databaseId}}" {
|
|
147
|
+
project = "{{projectId}}"
|
|
148
|
+
name = "{{databaseId}}"
|
|
149
|
+
location_id = "{{region}}"
|
|
150
|
+
type = "FIRESTORE_NATIVE"
|
|
151
|
+
|
|
152
|
+
concurrency_mode = "OPTIMISTIC"
|
|
153
|
+
app_engine_integration_mode = "DISABLED"
|
|
154
|
+
|
|
155
|
+
depends_on = [google_project_service.firestore]
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
{{#if enableVpc}}
|
|
159
|
+
# VPC Access Connector for private networking
|
|
160
|
+
resource "google_vpc_access_connector" "connector" {
|
|
161
|
+
name = "{{functionName}}-vpc-connector"
|
|
162
|
+
region = "{{region}}"
|
|
163
|
+
project = "{{projectId}}"
|
|
164
|
+
ip_cidr_range = "10.8.0.0/28"
|
|
165
|
+
network = var.vpc_network
|
|
166
|
+
}
|
|
167
|
+
{{/if}}
|
|
168
|
+
|
|
169
|
+
{{#if enableSecretManager}}
|
|
170
|
+
# Secret Manager for sensitive configuration
|
|
171
|
+
resource "google_secret_manager_secret" "{{snakeCase functionName}}_secrets" {
|
|
172
|
+
secret_id = "{{functionName}}-secrets"
|
|
173
|
+
project = "{{projectId}}"
|
|
174
|
+
|
|
175
|
+
replication {
|
|
176
|
+
auto {}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
labels = {
|
|
180
|
+
environment = "{{environment}}"
|
|
181
|
+
managed_by = "terraform"
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# IAM binding for Secret Manager access
|
|
186
|
+
resource "google_secret_manager_secret_iam_member" "secret_accessor" {
|
|
187
|
+
project = google_secret_manager_secret.{{snakeCase functionName}}_secrets.project
|
|
188
|
+
secret_id = google_secret_manager_secret.{{snakeCase functionName}}_secrets.secret_id
|
|
189
|
+
role = "roles/secretmanager.secretAccessor"
|
|
190
|
+
member = "serviceAccount:${google_service_account.{{snakeCase serviceAccountId}}.email}"
|
|
191
|
+
}
|
|
192
|
+
{{/if}}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Output Values for GCP Cloud Functions + Firestore
|
|
2
|
+
# Generated by SpecWeave Serverless Architecture Intelligence
|
|
3
|
+
|
|
4
|
+
output "function_name" {
|
|
5
|
+
description = "Cloud Function name"
|
|
6
|
+
value = google_cloudfunctions2_function.{{snakeCase functionName}}.name
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
output "function_id" {
|
|
10
|
+
description = "Cloud Function ID"
|
|
11
|
+
value = google_cloudfunctions2_function.{{snakeCase functionName}}.id
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
output "function_url" {
|
|
15
|
+
description = "Cloud Function HTTPS trigger URL"
|
|
16
|
+
value = google_cloudfunctions2_function.{{snakeCase functionName}}.service_config[0].uri
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
output "function_region" {
|
|
20
|
+
description = "Cloud Function region"
|
|
21
|
+
value = google_cloudfunctions2_function.{{snakeCase functionName}}.location
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
output "service_account_email" {
|
|
25
|
+
description = "Service Account email for Cloud Function"
|
|
26
|
+
value = google_service_account.{{snakeCase serviceAccountId}}.email
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
output "firestore_database_name" {
|
|
30
|
+
description = "Firestore database name"
|
|
31
|
+
value = google_firestore_database.{{snakeCase databaseId}}.name
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
output "firestore_location" {
|
|
35
|
+
description = "Firestore database location"
|
|
36
|
+
value = google_firestore_database.{{snakeCase databaseId}}.location_id
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
output "storage_bucket_name" {
|
|
40
|
+
description = "Storage bucket name for function source code"
|
|
41
|
+
value = google_storage_bucket.{{snakeCase bucketName}}.name
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
output "storage_bucket_url" {
|
|
45
|
+
description = "Storage bucket URL"
|
|
46
|
+
value = google_storage_bucket.{{snakeCase bucketName}}.url
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
{{#if enableSecretManager}}
|
|
50
|
+
output "secret_manager_secret_id" {
|
|
51
|
+
description = "Secret Manager secret ID"
|
|
52
|
+
value = google_secret_manager_secret.{{snakeCase functionName}}_secrets.secret_id
|
|
53
|
+
}
|
|
54
|
+
{{/if}}
|
|
55
|
+
|
|
56
|
+
{{#if enableVpc}}
|
|
57
|
+
output "vpc_connector_id" {
|
|
58
|
+
description = "VPC Access Connector ID"
|
|
59
|
+
value = google_vpc_access_connector.connector.id
|
|
60
|
+
}
|
|
61
|
+
{{/if}}
|
|
62
|
+
|
|
63
|
+
output "project_id" {
|
|
64
|
+
description = "GCP Project ID"
|
|
65
|
+
value = "{{projectId}}"
|
|
66
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Terraform Provider Configuration for GCP
|
|
2
|
+
# Generated by SpecWeave Serverless Architecture Intelligence
|
|
3
|
+
|
|
4
|
+
terraform {
|
|
5
|
+
required_version = ">= 1.5.0"
|
|
6
|
+
|
|
7
|
+
required_providers {
|
|
8
|
+
google = {
|
|
9
|
+
source = "hashicorp/google"
|
|
10
|
+
version = "~> 5.0"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
{{#if enableRemoteState}}
|
|
15
|
+
backend "gcs" {
|
|
16
|
+
bucket = "{{tfStateBucket}}"
|
|
17
|
+
prefix = "terraform/state/{{projectName}}-{{environment}}"
|
|
18
|
+
}
|
|
19
|
+
{{/if}}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
provider "google" {
|
|
23
|
+
project = "{{projectId}}"
|
|
24
|
+
region = "{{region}}"
|
|
25
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Input Variables for GCP Cloud Functions + Firestore
|
|
2
|
+
# Generated by SpecWeave Serverless Architecture Intelligence
|
|
3
|
+
|
|
4
|
+
variable "project_id" {
|
|
5
|
+
description = "GCP Project ID"
|
|
6
|
+
type = string
|
|
7
|
+
default = "{{projectId}}"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
variable "region" {
|
|
11
|
+
description = "GCP region for all resources"
|
|
12
|
+
type = string
|
|
13
|
+
default = "{{region}}"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
variable "function_name" {
|
|
17
|
+
description = "Cloud Function name"
|
|
18
|
+
type = string
|
|
19
|
+
default = "{{functionName}}"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
variable "runtime" {
|
|
23
|
+
description = "Cloud Function runtime (nodejs20, python312, go121, etc.)"
|
|
24
|
+
type = string
|
|
25
|
+
default = "{{runtime}}"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
variable "entry_point" {
|
|
29
|
+
description = "Function entry point (handler function name)"
|
|
30
|
+
type = string
|
|
31
|
+
default = "{{entryPoint}}"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
variable "memory_mb" {
|
|
35
|
+
description = "Memory allocation in MB (128-32768)"
|
|
36
|
+
type = number
|
|
37
|
+
default = {{memoryMb}}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
variable "timeout_seconds" {
|
|
41
|
+
description = "Function timeout in seconds (1-3600)"
|
|
42
|
+
type = number
|
|
43
|
+
default = {{timeoutSeconds}}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
variable "min_instances" {
|
|
47
|
+
description = "Minimum number of instances (0 for auto-scale to zero)"
|
|
48
|
+
type = number
|
|
49
|
+
default = {{minInstances}}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
variable "max_instances" {
|
|
53
|
+
description = "Maximum number of instances"
|
|
54
|
+
type = number
|
|
55
|
+
default = {{maxInstances}}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
variable "environment" {
|
|
59
|
+
description = "Environment name (dev, staging, prod)"
|
|
60
|
+
type = string
|
|
61
|
+
default = "{{environment}}"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
variable "database_id" {
|
|
65
|
+
description = "Firestore database ID"
|
|
66
|
+
type = string
|
|
67
|
+
default = "{{databaseId}}"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
variable "collection_id" {
|
|
71
|
+
description = "Firestore collection ID"
|
|
72
|
+
type = string
|
|
73
|
+
default = "{{collectionId}}"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
variable "service_account_id" {
|
|
77
|
+
description = "Service Account ID for Cloud Function"
|
|
78
|
+
type = string
|
|
79
|
+
default = "{{serviceAccountId}}"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
variable "cors_origins" {
|
|
83
|
+
description = "List of allowed CORS origins"
|
|
84
|
+
type = list(string)
|
|
85
|
+
default = {{tfList corsOrigins}}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
variable "project_name" {
|
|
89
|
+
description = "Project name for resource labeling"
|
|
90
|
+
type = string
|
|
91
|
+
default = "{{projectName}}"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
variable "bucket_name" {
|
|
95
|
+
description = "Storage bucket name for function source code"
|
|
96
|
+
type = string
|
|
97
|
+
default = "{{bucketName}}"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
variable "bucket_location" {
|
|
101
|
+
description = "Storage bucket location (US, EU, ASIA, or region)"
|
|
102
|
+
type = string
|
|
103
|
+
default = "{{bucketLocation}}"
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
{{#if enableConcurrency}}
|
|
107
|
+
variable "max_concurrent_requests" {
|
|
108
|
+
description = "Maximum concurrent requests per instance"
|
|
109
|
+
type = number
|
|
110
|
+
default = {{maxConcurrentRequests}}
|
|
111
|
+
}
|
|
112
|
+
{{/if}}
|
|
113
|
+
|
|
114
|
+
{{#if enableVpc}}
|
|
115
|
+
variable "vpc_network" {
|
|
116
|
+
description = "VPC network name for private networking"
|
|
117
|
+
type = string
|
|
118
|
+
}
|
|
119
|
+
{{/if}}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"projectName": "my-supabase-project",
|
|
3
|
+
"orgId": "your-org-id",
|
|
4
|
+
"region": "us-east-1",
|
|
5
|
+
"databasePassword": "changeme123",
|
|
6
|
+
"planType": "free",
|
|
7
|
+
"environment": "dev",
|
|
8
|
+
"enableAuth": true,
|
|
9
|
+
"enableStorage": true,
|
|
10
|
+
"enableRealtime": true,
|
|
11
|
+
"enableEdgeFunctions": true,
|
|
12
|
+
"storageBuckets": ["avatars", "documents"],
|
|
13
|
+
"authProviders": ["email"],
|
|
14
|
+
"postgresVersion": "15"
|
|
15
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Supabase (PostgreSQL + Auth + Storage + Edge Functions) Configuration
|
|
2
|
+
|
|
3
|
+
**Generated by SpecWeave Serverless Architecture Intelligence**
|
|
4
|
+
|
|
5
|
+
Supabase provides complete backend-as-a-service:
|
|
6
|
+
- PostgreSQL database (Postgres {{postgresVersion}})
|
|
7
|
+
- Built-in Auth ({{authProviders}})
|
|
8
|
+
- Object Storage
|
|
9
|
+
- Edge Functions (Deno runtime)
|
|
10
|
+
- Realtime subscriptions
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
1. Install Supabase CLI: `npm install -g supabase`
|
|
15
|
+
2. Login: `supabase login`
|
|
16
|
+
3. Get Org ID: `supabase orgs list`
|
|
17
|
+
|
|
18
|
+
## Deployment
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Initialize Supabase
|
|
22
|
+
supabase init
|
|
23
|
+
|
|
24
|
+
# Link to project
|
|
25
|
+
supabase link --project-ref {{projectName}}
|
|
26
|
+
|
|
27
|
+
# Deploy database migrations
|
|
28
|
+
supabase db push
|
|
29
|
+
|
|
30
|
+
# Deploy edge functions
|
|
31
|
+
supabase functions deploy
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Cost: $0/month (Free Tier)
|
|
35
|
+
|
|
36
|
+
Supabase free tier includes:
|
|
37
|
+
- 500 MB database storage
|
|
38
|
+
- 1 GB file storage
|
|
39
|
+
- 2 GB bandwidth
|
|
40
|
+
- 50,000 monthly active users
|
|
41
|
+
- 500,000 Edge Function invocations
|
|
42
|
+
|
|
43
|
+
## Support
|
|
44
|
+
|
|
45
|
+
- Supabase Docs: https://supabase.com/docs
|
|
46
|
+
- SpecWeave: https://spec-weave.com
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Supabase (Database + Auth + Storage + Edge Functions) Configuration
|
|
2
|
+
# Generated by SpecWeave Serverless Architecture Intelligence
|
|
3
|
+
#
|
|
4
|
+
# Note: Supabase doesn't have official Terraform provider yet.
|
|
5
|
+
# This uses Supabase CLI with null_resource provisioners.
|
|
6
|
+
# For production, use Supabase Management API or wait for official provider.
|
|
7
|
+
|
|
8
|
+
# Supabase Project (using CLI)
|
|
9
|
+
resource "null_resource" "supabase_project" {
|
|
10
|
+
provisioner "local-exec" {
|
|
11
|
+
command = <<-EOT
|
|
12
|
+
supabase projects create {{projectName}} \
|
|
13
|
+
--org-id {{orgId}} \
|
|
14
|
+
--region {{region}} \
|
|
15
|
+
--plan {{planType}} \
|
|
16
|
+
--db-password '{{databasePassword}}'
|
|
17
|
+
EOT
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
provisioner "local-exec" {
|
|
21
|
+
when = destroy
|
|
22
|
+
command = "supabase projects delete {{projectName}} --org-id {{orgId}}"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Storage Buckets
|
|
27
|
+
{{#each storageBuckets}}
|
|
28
|
+
resource "null_resource" "storage_bucket_{{this}}" {
|
|
29
|
+
provisioner "local-exec" {
|
|
30
|
+
command = <<-EOT
|
|
31
|
+
supabase storage create {{this}} \
|
|
32
|
+
--project-ref {{projectName}} \
|
|
33
|
+
--public
|
|
34
|
+
EOT
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
depends_on = [null_resource.supabase_project]
|
|
38
|
+
}
|
|
39
|
+
{{/each}}
|
|
40
|
+
|
|
41
|
+
# Edge Functions
|
|
42
|
+
{{#if enableEdgeFunctions}}
|
|
43
|
+
resource "null_resource" "edge_functions" {
|
|
44
|
+
provisioner "local-exec" {
|
|
45
|
+
command = "supabase functions deploy --project-ref {{projectName}}"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
depends_on = [null_resource.supabase_project]
|
|
49
|
+
}
|
|
50
|
+
{{/if}}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { AdoClientV2 } from "./ado-client-v2.js";
|
|
2
|
+
import { EnhancedContentBuilder } from "../../../src/core/sync/enhanced-content-builder.js";
|
|
3
|
+
import { SpecIncrementMapper } from "../../../src/core/sync/spec-increment-mapper.js";
|
|
4
|
+
import { parseSpecContent } from "../../../src/core/spec-content-sync.js";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
async function syncSpecToAdoWithEnhancedContent(options) {
|
|
8
|
+
const { specPath, organization, project, dryRun = false, verbose = false } = options;
|
|
9
|
+
try {
|
|
10
|
+
const baseSpec = await parseSpecContent(specPath);
|
|
11
|
+
if (!baseSpec) {
|
|
12
|
+
return {
|
|
13
|
+
success: false,
|
|
14
|
+
action: "error",
|
|
15
|
+
error: "Failed to parse spec content"
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (verbose) {
|
|
19
|
+
console.log(`\u{1F4C4} Parsed spec: ${baseSpec.identifier.compact}`);
|
|
20
|
+
}
|
|
21
|
+
const specId = baseSpec.identifier.full || baseSpec.identifier.compact;
|
|
22
|
+
const rootDir = await findSpecWeaveRoot(specPath);
|
|
23
|
+
const mapper = new SpecIncrementMapper(rootDir);
|
|
24
|
+
const mapping = await mapper.mapSpecToIncrements(specId);
|
|
25
|
+
if (verbose) {
|
|
26
|
+
console.log(`\u{1F517} Found ${mapping.increments.length} related increments`);
|
|
27
|
+
}
|
|
28
|
+
const taskMapping = buildTaskMapping(mapping.increments, organization, project);
|
|
29
|
+
const architectureDocs = await findArchitectureDocs(rootDir, specId);
|
|
30
|
+
const enhancedSpec = {
|
|
31
|
+
...baseSpec,
|
|
32
|
+
summary: baseSpec.description,
|
|
33
|
+
taskMapping,
|
|
34
|
+
architectureDocs
|
|
35
|
+
};
|
|
36
|
+
const builder = new EnhancedContentBuilder();
|
|
37
|
+
const description = builder.buildExternalDescription(enhancedSpec);
|
|
38
|
+
if (verbose) {
|
|
39
|
+
console.log(`\u{1F4DD} Generated description: ${description.length} characters`);
|
|
40
|
+
}
|
|
41
|
+
if (dryRun) {
|
|
42
|
+
console.log("\u{1F50D} DRY RUN - Would create/update feature with:");
|
|
43
|
+
console.log(` Title: ${baseSpec.title}`);
|
|
44
|
+
console.log(` Description length: ${description.length}`);
|
|
45
|
+
return {
|
|
46
|
+
success: true,
|
|
47
|
+
action: "no-change",
|
|
48
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (!organization || !project) {
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
action: "error",
|
|
55
|
+
error: "Azure DevOps organization/project not specified"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const profile = {
|
|
59
|
+
provider: "ado",
|
|
60
|
+
displayName: `${organization}/${project}`,
|
|
61
|
+
config: {
|
|
62
|
+
organization,
|
|
63
|
+
project
|
|
64
|
+
},
|
|
65
|
+
timeRange: { default: "1M", max: "6M" }
|
|
66
|
+
};
|
|
67
|
+
const pat = process.env.AZURE_DEVOPS_PAT || "";
|
|
68
|
+
const client = new AdoClientV2(profile, pat);
|
|
69
|
+
const existingFeature = await findExistingFeature(client, baseSpec.identifier.compact);
|
|
70
|
+
let result;
|
|
71
|
+
if (existingFeature) {
|
|
72
|
+
await client.updateWorkItem(existingFeature.id, {
|
|
73
|
+
title: `[${baseSpec.identifier.compact}] ${baseSpec.title}`,
|
|
74
|
+
description
|
|
75
|
+
});
|
|
76
|
+
result = {
|
|
77
|
+
success: true,
|
|
78
|
+
action: "updated",
|
|
79
|
+
featureId: existingFeature.id,
|
|
80
|
+
featureUrl: `https://dev.azure.com/${organization}/${project}/_workitems/edit/${existingFeature.id}`,
|
|
81
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
82
|
+
};
|
|
83
|
+
} else {
|
|
84
|
+
const feature = await client.createEpic({
|
|
85
|
+
title: `[${baseSpec.identifier.compact}] ${baseSpec.title}`,
|
|
86
|
+
description,
|
|
87
|
+
tags: ["spec", "external-tool-sync"]
|
|
88
|
+
});
|
|
89
|
+
result = {
|
|
90
|
+
success: true,
|
|
91
|
+
action: "created",
|
|
92
|
+
featureId: feature.id,
|
|
93
|
+
featureUrl: `https://dev.azure.com/${organization}/${project}/_workitems/edit/${feature.id}`,
|
|
94
|
+
tasksLinked: taskMapping?.tasks.length || 0
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (verbose) {
|
|
98
|
+
console.log(`\u2705 ${result.action === "created" ? "Created" : "Updated"} feature #${result.featureId}`);
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
action: "error",
|
|
105
|
+
error: error.message
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function findSpecWeaveRoot(specPath) {
|
|
110
|
+
let currentDir = path.dirname(specPath);
|
|
111
|
+
while (true) {
|
|
112
|
+
const specweaveDir = path.join(currentDir, ".specweave");
|
|
113
|
+
try {
|
|
114
|
+
await fs.access(specweaveDir);
|
|
115
|
+
return currentDir;
|
|
116
|
+
} catch {
|
|
117
|
+
const parentDir = path.dirname(currentDir);
|
|
118
|
+
if (parentDir === currentDir) {
|
|
119
|
+
throw new Error(".specweave directory not found");
|
|
120
|
+
}
|
|
121
|
+
currentDir = parentDir;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function buildTaskMapping(increments, organization, project) {
|
|
126
|
+
if (increments.length === 0) return void 0;
|
|
127
|
+
const firstIncrement = increments[0];
|
|
128
|
+
const tasks = firstIncrement.tasks.map((task) => ({
|
|
129
|
+
id: task.id,
|
|
130
|
+
title: task.title,
|
|
131
|
+
userStories: task.userStories
|
|
132
|
+
}));
|
|
133
|
+
return {
|
|
134
|
+
incrementId: firstIncrement.id,
|
|
135
|
+
tasks,
|
|
136
|
+
tasksUrl: `https://dev.azure.com/${organization}/${project}/_git/repo?path=/.specweave/increments/${firstIncrement.id}/tasks.md`
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async function findArchitectureDocs(rootDir, specId) {
|
|
140
|
+
const docs = [];
|
|
141
|
+
const archDir = path.join(rootDir, ".specweave/docs/internal/architecture");
|
|
142
|
+
try {
|
|
143
|
+
const adrDir = path.join(archDir, "adr");
|
|
144
|
+
try {
|
|
145
|
+
const adrs = await fs.readdir(adrDir);
|
|
146
|
+
const relatedAdrs = adrs.filter((file) => file.includes(specId.replace("spec-", "")));
|
|
147
|
+
for (const adr of relatedAdrs) {
|
|
148
|
+
docs.push({
|
|
149
|
+
type: "adr",
|
|
150
|
+
path: path.join(adrDir, adr),
|
|
151
|
+
title: adr.replace(".md", "").replace(/-/g, " ")
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
158
|
+
return docs;
|
|
159
|
+
}
|
|
160
|
+
async function findExistingFeature(client, specId) {
|
|
161
|
+
try {
|
|
162
|
+
const features = await client.queryWorkItems(`[System.Title] Contains '[${specId}]' AND [System.WorkItemType] = 'Feature'`);
|
|
163
|
+
return features[0] || null;
|
|
164
|
+
} catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export {
|
|
169
|
+
syncSpecToAdoWithEnhancedContent
|
|
170
|
+
};
|