@tdk-landscape/tdk-cli-core 1.3.15 → 1.3.26
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/Tiltfile +144 -0
- package/discovery/AGENTS.md +362 -0
- package/discovery/TILT_DISCOVERY.star +424 -0
- package/discovery/Tiltfile +58 -0
- package/discovery/config.star +258 -0
- package/discovery/constants.star +127 -0
- package/discovery/deterministic.star +211 -0
- package/discovery/discovery_daemon.star +191 -0
- package/discovery/discovery_orchestrator.star +460 -0
- package/discovery/filtering.star +5 -0
- package/discovery/identity-management-backend/service.yaml +26 -0
- package/discovery/identity-management-frontend/service.yaml +29 -0
- package/discovery/identity-sdk/service.yaml +9 -0
- package/discovery/incremental_discovery.star +213 -0
- package/discovery/indexing.star +7 -0
- package/discovery/json_manifest_scanner.star +51 -0
- package/discovery/libraries.star +46 -0
- package/discovery/loading.star +23 -0
- package/discovery/manifest/constants.star +104 -0
- package/discovery/manifest/loading.star +386 -0
- package/discovery/manifest/normalize.star +281 -0
- package/discovery/manifest/validation.star +108 -0
- package/discovery/normalization.star +11 -0
- package/discovery/registry.star +544 -0
- package/discovery/resource_snapshot.py +382 -0
- package/discovery/resource_snapshot.star +143 -0
- package/discovery/schemas.star +1 -0
- package/discovery/services/platform/cdc/debezium/nats-connector/service.yaml +9 -0
- package/discovery/services/platform/cdc/nats-http-bridge/service.yaml +9 -0
- package/discovery/services/platform/orchestrator/orchestrator-glue-backend/service.yaml +26 -0
- package/discovery/services/platform/synthetic-monitor/service.yaml +9 -0
- package/discovery/test_resource_snapshot.py +251 -0
- package/discovery/validation.star +78 -0
- package/discovery/versioning.star +1 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +11 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +1 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +36 -41
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/resource.d.ts.map +1 -1
- package/dist/commands/resource.js +51 -55
- package/dist/commands/resource.js.map +1 -1
- package/dist/commands/stack.d.ts.map +1 -1
- package/dist/commands/stack.js +22 -24
- package/dist/commands/stack.js.map +1 -1
- package/dist/commands/ui.d.ts.map +1 -1
- package/dist/commands/ui.js +1 -2
- package/dist/commands/ui.js.map +1 -1
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +1 -2
- package/dist/commands/up.js.map +1 -1
- package/dist/commands/upgrade.d.ts +8 -0
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +59 -18
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/generator/extension-fetch.d.ts +19 -0
- package/dist/generator/extension-fetch.d.ts.map +1 -1
- package/dist/generator/extension-fetch.js +71 -5
- package/dist/generator/extension-fetch.js.map +1 -1
- package/dist/generator/template-engine.d.ts +1 -0
- package/dist/generator/template-engine.d.ts.map +1 -1
- package/dist/generator/template-engine.js +50 -6
- package/dist/generator/template-engine.js.map +1 -1
- package/dist/utils/command-helpers.d.ts.map +1 -1
- package/dist/utils/command-helpers.js +7 -9
- package/dist/utils/command-helpers.js.map +1 -1
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +1 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/errors.d.ts +2 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +6 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/project-features.d.ts.map +1 -1
- package/dist/utils/project-features.js +1 -1
- package/dist/utils/project-features.js.map +1 -1
- package/dist/utils/resource-features.d.ts.map +1 -1
- package/dist/utils/resource-features.js +2 -2
- package/dist/utils/resource-features.js.map +1 -1
- package/dist/utils/tar.js +4 -4
- package/dist/utils/tar.js.map +1 -1
- package/dist/utils/validation.d.ts +7 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +9 -0
- package/dist/utils/validation.js.map +1 -1
- package/engine/AGENTS.md +705 -0
- package/engine/README.md +29 -0
- package/engine/REFACTORING_MANIFEST_SYSTEM.md +974 -0
- package/engine/Tiltfile +80 -0
- package/engine/assets/docker/golden-layers.Dockerfile +221 -0
- package/engine/assets/scripts/cleanup-completed-migrator-images.sh +37 -0
- package/engine/assets/scripts/cleanup-tilt-images.sh +120 -0
- package/engine/assets/scripts/mac-m1-resource-monitor.sh +121 -0
- package/engine/config.star +3 -0
- package/engine/docs/AUTODISCOVERY_TEST.md +182 -0
- package/engine/docs/C4-ARCHITECTURE-operations.md +396 -0
- package/engine/docs/C4-ARCHITECTURE-overview.md +284 -0
- package/engine/docs/C4-ARCHITECTURE.md +17 -0
- package/engine/docs/GOLDEN_IMAGE_INTEGRATION.md +349 -0
- package/engine/docs/MANIFEST_DRIVEN_ARCHITECTURE.md +357 -0
- package/engine/docs/README.md +284 -0
- package/engine/entrypoint.star +97 -0
- package/engine/lifecycle/orchestrator.star +260 -0
- package/engine/paths.star +717 -0
- package/engine/schemas/manifest-schema.json +301 -0
- package/engine/schemas/service-schema.json +301 -0
- package/engine/scripts/README.md +89 -0
- package/engine/scripts/build-and-publish-lib.sh +205 -0
- package/engine/scripts/check-lib-publish.sh +85 -0
- package/engine/scripts/debug-container.sh +258 -0
- package/engine/scripts/generate-manifest.sh +197 -0
- package/engine/spec.master +702 -0
- package/engine/spec.master.example +341 -0
- package/engine/topologies/README.md +34 -0
- package/engine/topologies/platform/docker/AGENTS.md +59 -0
- package/engine/topologies/platform/docker/auth/auth.star +167 -0
- package/engine/topologies/platform/docker/build/golden_image.star +37 -0
- package/engine/topologies/platform/docker/build/golden_image_build.star +82 -0
- package/engine/topologies/platform/docker/build/golden_image_constants.star +93 -0
- package/engine/topologies/platform/docker/build/golden_image_dockerfile.star +291 -0
- package/engine/topologies/platform/docker/compose/compose.star +636 -0
- package/engine/topologies/platform/docker/compose/compose_helpers.star +52 -0
- package/engine/topologies/platform/docker/compose/traefik_standalone.star +53 -0
- package/engine/topologies/platform/docker/config/bunignore.star +142 -0
- package/engine/topologies/platform/docker/config/dockerignore.star +150 -0
- package/engine/topologies/platform/docker/constants.star +170 -0
- package/engine/topologies/platform/docker/dockerfile/dockerfile.star +54 -0
- package/engine/topologies/platform/docker/generators/golden_docker_generator_v2.star +73 -0
- package/engine/topologies/platform/docker/index.star +27 -0
- package/engine/topologies/platform/docker/layers/bun_helpers.star +23 -0
- package/engine/topologies/platform/docker/layers/infisical/index.star +40 -0
- package/engine/topologies/platform/docker/layers/infisical/infisical_docker.star +262 -0
- package/engine/topologies/platform/docker/layers/l1_base_layers.star +87 -0
- package/engine/topologies/platform/docker/layers/l2_dependency_layers.star +125 -0
- package/engine/topologies/platform/docker/layers/l3_builder_layers.star +209 -0
- package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +214 -0
- package/engine/topologies/platform/docker/layers/prisma/constants.star +135 -0
- package/engine/topologies/platform/docker/layers/prisma/db_readiness.star +96 -0
- package/engine/topologies/platform/docker/layers/prisma/filesystem_setup.star +109 -0
- package/engine/topologies/platform/docker/layers/prisma/migrate_script.star +98 -0
- package/engine/topologies/platform/docker/layers/prisma/prisma_build.star +126 -0
- package/engine/topologies/platform/docker/layers/prisma/prisma_runtime.star +161 -0
- package/engine/topologies/platform/docker/layers/prisma/secret_resolution.star +119 -0
- package/engine/topologies/platform/docker/networking/api_path_constants.star +230 -0
- package/engine/topologies/platform/docker/networking/sablier_container_cycle.star +27 -0
- package/engine/topologies/platform/docker/networking/traefik.star +232 -0
- package/engine/topologies/platform/docker/networking/traefik_constants.star +146 -0
- package/engine/topologies/platform/docker/networking/traefik_helpers.star +160 -0
- package/engine/topologies/platform/docker/secrets/infisical.star +135 -0
- package/engine/topologies/platform/net/proxy.star +4 -0
- package/engine/topologies/platform/registries/local.star +4 -0
- package/engine/topologies/platform/security/secrets.star +239 -0
- package/engine/topologies/platform/state/relational.star +4 -0
- package/engine/topologies/tilt/common/AGENTS.md +59 -0
- package/engine/topologies/tilt/common/utils.star +364 -0
- package/engine/topologies/tilt/common/utils_debug.star +69 -0
- package/engine/topologies/tilt/common/utils_deterministic.star +168 -0
- package/engine/topologies/tilt/common/utils_docker_networks.star +46 -0
- package/engine/topologies/tilt/common/utils_env.star +43 -0
- package/engine/topologies/tilt/common/utils_output.star +97 -0
- package/engine/topologies/tilt/config/AGENTS.md +68 -0
- package/engine/topologies/tilt/config/defaults.star +3 -0
- package/engine/topologies/tilt/config/feature_flags.star +10 -0
- package/engine/topologies/tilt/config/global.star +55 -0
- package/engine/topologies/tilt/config/profiles.star +382 -0
- package/engine/topologies/tilt/generators/agents_md.star +62 -0
- package/engine/topologies/tilt/generators/api_gateway.star +145 -0
- package/engine/topologies/tilt/generators/index.star +124 -0
- package/engine/topologies/tilt/generators/infisical/README.md +424 -0
- package/engine/topologies/tilt/generators/infisical/examples.star +312 -0
- package/engine/topologies/tilt/generators/infisical/index.star +57 -0
- package/engine/topologies/tilt/generators/infisical/machine_identity.star +420 -0
- package/engine/topologies/tilt/generators/infisical/organization.star +534 -0
- package/engine/topologies/tilt/generators/infisical/path_manager.star +476 -0
- package/engine/topologies/tilt/generators/infisical/secrets_generator.star +420 -0
- package/engine/topologies/tilt/generators/nginx_conf.star +143 -0
- package/engine/topologies/tilt/generators/npmrc.star +111 -0
- package/engine/topologies/tilt/generators/tsconfig.star +23 -0
- package/engine/topologies/tilt/generators/typescript/backend_library_tsconfig.star +71 -0
- package/engine/topologies/tilt/generators/typescript/backend_tsconfig.star +124 -0
- package/engine/topologies/tilt/generators/typescript/common.star +7 -0
- package/engine/topologies/tilt/generators/typescript/frontend_library_tsconfig.star +76 -0
- package/engine/topologies/tilt/generators/typescript/frontend_tsconfig.star +110 -0
- package/engine/topologies/tilt/generators/typescript/include.star +23 -0
- package/engine/topologies/tilt/generators/typescript/playwright_config.star +40 -0
- package/engine/topologies/tilt/generators/typescript/prisma_config.star +49 -0
- package/engine/topologies/tilt/generators/validators.star +853 -0
- package/engine/topologies/tilt/generators/vite/backend.star +78 -0
- package/engine/topologies/tilt/generators/vite/frontend.star +98 -0
- package/engine/topologies/tilt/generators/vite/generators.star +43 -0
- package/engine/topologies/tilt/generators/vite/helpers.star +244 -0
- package/engine/topologies/tilt/generators/vite/library.star +65 -0
- package/engine/topologies/tilt/generators/vite/sdk.star +73 -0
- package/engine/topologies/tilt/generators/vite/templates.star +737 -0
- package/engine/topologies/tilt/generators/vite_config.star +22 -0
- package/engine/topologies/tilt/manifest/AGENTS.md +61 -0
- package/engine/topologies/tilt/manifest/README.md +693 -0
- package/engine/topologies/tilt/manifest/__init__.star +218 -0
- package/engine/topologies/tilt/manifest/constants.star +252 -0
- package/engine/topologies/tilt/manifest/errors.star +266 -0
- package/engine/topologies/tilt/manifest/integration.star +339 -0
- package/engine/topologies/tilt/manifest/json_to_yaml.py +54 -0
- package/engine/topologies/tilt/manifest/loader.star +214 -0
- package/engine/topologies/tilt/manifest/mapper.star +227 -0
- package/engine/topologies/tilt/manifest/parser.star +400 -0
- package/engine/topologies/tilt/manifest/schema.star +462 -0
- package/engine/topologies/tilt/manifest/tests/test_integration.star +276 -0
- package/engine/topologies/tilt/manifest/tests/test_loader_parser.star +397 -0
- package/engine/topologies/tilt/manifest/tests/test_manifest.star +316 -0
- package/engine/topologies/tilt/manifest/tests/test_validator.star +470 -0
- package/engine/topologies/tilt/manifest/validator.star +717 -0
- package/engine/topologies/tilt/manifest/yaml_to_json.py +18 -0
- package/engine/topologies/tilt/resources/AGENTS.md +71 -0
- package/engine/topologies/tilt/resources/conditions.star +3 -0
- package/engine/topologies/tilt/resources/databases.star +244 -0
- package/engine/topologies/tilt/resources/declaration.star +3 -0
- package/engine/topologies/tilt/resources/deps.star +3 -0
- package/engine/topologies/tilt/resources/infra-loader.star +437 -0
- package/engine/topologies/tilt/resources/libs.star +30 -0
- package/engine/topologies/tilt/resources/libs_discovery.star +102 -0
- package/engine/topologies/tilt/resources/libs_paths.star +79 -0
- package/engine/topologies/tilt/resources/libs_resource_definition.star +151 -0
- package/engine/topologies/tilt/resources/libs_setup.star +164 -0
- package/engine/topologies/tilt/resources/libs_tsconfig.star +37 -0
- package/engine/topologies/tilt/resources/orchestrator/apply.star +77 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +431 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_manifest_orchestration.star +81 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_migrator_orchestration.star +148 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_resource_validation.star +36 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_runtime_flags.star +44 -0
- package/engine/topologies/tilt/resources/orchestrator/builders/typescript.star +164 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/AGENTS.md +75 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/index.star +21 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/resolver.star +134 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/env.star +258 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/frontend.star +169 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +524 -0
- package/engine/topologies/tilt/resources/orchestrator/helpers.star +33 -0
- package/engine/topologies/tilt/resources/orchestrator.star +54 -0
- package/engine/topologies/tilt/resources/ordering.star +3 -0
- package/engine/topologies/tilt/resources/triggers.star +3 -0
- package/engine/topologies/tilt/resources/watchers.star +299 -0
- package/engine/where-things-live.star +717 -0
- package/ext/Tiltfile +66 -0
- package/ext/ide-components/README.md +219 -0
- package/ext/ide-components/code_executor/server.py +268 -0
- package/ext/ide-components/code_viewer/server.py +206 -0
- package/ext/ide-components/config_inspector/server.py +1050 -0
- package/ext/ide-components/file_browser/server.py +285 -0
- package/ext/ide-components/shared/config_service.py +469 -0
- package/ext/ide-components/shared/file_utils.py +298 -0
- package/ext/ide-components/shared/http_utils.py +232 -0
- package/ext/ide-components/shared/static/styles.css +1334 -0
- package/ext/ide-components/shared/syntax_highlighter.py +140 -0
- package/ext/ide-components/shared/template_engine.py +123 -0
- package/ext/ide-components/shared/templates/base.html +121 -0
- package/ext/ide-components/shared/test_config_service.py +326 -0
- package/ext/ide-components/shared/tilt_integration.py +158 -0
- package/ext/ui-enhancements/cron-status-server.sh +49 -0
- package/ext/ui-enhancements/cron-status-tracker.sh +146 -0
- package/ext/ui-enhancements/extension.yaml +36 -0
- package/ext/ui-enhancements/tiltfile.py +99 -0
- package/ext/ui-enhancements/ui/cron-jobs-tab.css +396 -0
- package/ext/ui-enhancements/ui/help-panel.css +279 -0
- package/ext/ui-enhancements/ui/icons.css +125 -0
- package/ext/ui-enhancements/ui/tooltips.css +114 -0
- package/package.json +13 -9
- package/specs/specs/TILT_SERVICE_DEFAULTS.star +205 -0
- package/specs/specs/TILT_TECH_STACK.star +159 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Service Snapshot Utility
|
|
4
|
+
|
|
5
|
+
Manages the snapshot file used for incremental service discovery.
|
|
6
|
+
The snapshot tracks which services have been discovered to detect
|
|
7
|
+
new services added while Tilt is running.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
import hashlib
|
|
14
|
+
import logging
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import List, Dict, Set, Tuple, Optional
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
|
+
|
|
19
|
+
# Configure logging
|
|
20
|
+
logging.basicConfig(level=logging.WARNING, format='%(levelname)s: %(message)s')
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
SNAPSHOT_FILE = Path(".tdk/.tdk-out/snapshots/resource-snapshot.json")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def compute_resource_hash(resource_path: str) -> Optional[str]:
|
|
27
|
+
"""
|
|
28
|
+
Compute MD5 hash of a service.json file for efficient change detection.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
resource_path: Path to service.json file
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
MD5 hash string or None if file cannot be read
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
with open(resource_path, 'rb') as f:
|
|
38
|
+
content = f.read()
|
|
39
|
+
return hashlib.md5(content).hexdigest()[:16] # First 16 chars sufficient
|
|
40
|
+
except (IOError, OSError) as e:
|
|
41
|
+
logger.warning(f"Could not compute hash for {resource_path}: {e}")
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def compute_services_hash(services: List[str]) -> str:
|
|
46
|
+
"""
|
|
47
|
+
Compute aggregate hash of all services for quick comparison.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
services: List of service paths
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Aggregate hash string
|
|
54
|
+
"""
|
|
55
|
+
hasher = hashlib.md5()
|
|
56
|
+
for svc in sorted(services):
|
|
57
|
+
hasher.update(svc.encode())
|
|
58
|
+
svc_hash = compute_resource_hash(svc)
|
|
59
|
+
if svc_hash:
|
|
60
|
+
hasher.update(svc_hash.encode())
|
|
61
|
+
return hasher.hexdigest()[:16]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def save_snapshot(services: List[str], include_hashes: bool = True) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Save current service paths to snapshot file.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
services: List of service.json file paths
|
|
70
|
+
include_hashes: Whether to include content hashes for efficient comparison
|
|
71
|
+
"""
|
|
72
|
+
snapshot = {
|
|
73
|
+
"timestamp": datetime.now(timezone.utc).isoformat() + "Z",
|
|
74
|
+
"services": sorted(services),
|
|
75
|
+
"count": len(services)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Include aggregate hash for quick comparison
|
|
79
|
+
if services:
|
|
80
|
+
snapshot["hash"] = compute_services_hash(services)
|
|
81
|
+
|
|
82
|
+
# Include individual service hashes for change detection
|
|
83
|
+
if include_hashes and services:
|
|
84
|
+
resource_hashes = {}
|
|
85
|
+
for svc in services:
|
|
86
|
+
svc_hash = compute_resource_hash(svc)
|
|
87
|
+
if svc_hash:
|
|
88
|
+
resource_hashes[svc] = svc_hash
|
|
89
|
+
snapshot["resource_hashes"] = resource_hashes
|
|
90
|
+
|
|
91
|
+
# Ensure directory exists
|
|
92
|
+
SNAPSHOT_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
93
|
+
|
|
94
|
+
with open(SNAPSHOT_FILE, 'w') as f:
|
|
95
|
+
json.dump(snapshot, f, indent=2)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def load_snapshot() -> Dict:
|
|
99
|
+
"""
|
|
100
|
+
Load previous snapshot from file.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Snapshot dict with 'timestamp', 'services', 'count'.
|
|
104
|
+
Returns empty snapshot if file doesn't exist.
|
|
105
|
+
"""
|
|
106
|
+
if not SNAPSHOT_FILE.exists():
|
|
107
|
+
return {
|
|
108
|
+
"timestamp": None,
|
|
109
|
+
"services": [],
|
|
110
|
+
"count": 0
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
with open(SNAPSHOT_FILE, 'r') as f:
|
|
115
|
+
return json.load(f)
|
|
116
|
+
except json.JSONDecodeError as e:
|
|
117
|
+
logger.warning(f"Corrupted snapshot file {SNAPSHOT_FILE}: {e}")
|
|
118
|
+
return {
|
|
119
|
+
"timestamp": None,
|
|
120
|
+
"services": [],
|
|
121
|
+
"count": 0
|
|
122
|
+
}
|
|
123
|
+
except IOError as e:
|
|
124
|
+
logger.warning(f"Could not read snapshot file {SNAPSHOT_FILE}: {e}")
|
|
125
|
+
return {
|
|
126
|
+
"timestamp": None,
|
|
127
|
+
"services": [],
|
|
128
|
+
"count": 0
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def diff_snapshots(old: Dict, new: List[str], use_hashes: bool = True) -> Tuple[Set[str], Set[str], Set[str]]:
|
|
133
|
+
"""
|
|
134
|
+
Compare old snapshot with current services to find changes.
|
|
135
|
+
|
|
136
|
+
Uses hash-based comparison for efficient change detection when enabled.
|
|
137
|
+
Returns services that changed content even if path stayed the same.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
old: Previous snapshot dict
|
|
141
|
+
new: Current list of service paths
|
|
142
|
+
use_hashes: Whether to use hash-based comparison for efficiency
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
Tuple of (added_services, removed_services, modified_services) as sets
|
|
146
|
+
"""
|
|
147
|
+
old_services = set(old.get("services", []))
|
|
148
|
+
new_services = set(new)
|
|
149
|
+
|
|
150
|
+
added = new_services - old_services
|
|
151
|
+
removed = old_services - new_services
|
|
152
|
+
modified = set()
|
|
153
|
+
|
|
154
|
+
# Quick hash-based check - if aggregate hash matches, no changes
|
|
155
|
+
if use_hashes and "hash" in old and new:
|
|
156
|
+
current_hash = compute_services_hash(new)
|
|
157
|
+
if old["hash"] == current_hash:
|
|
158
|
+
return set(), set(), set() # No changes at all
|
|
159
|
+
|
|
160
|
+
# Check for modified services (same path, different content)
|
|
161
|
+
if use_hashes and "resource_hashes" in old:
|
|
162
|
+
old_hashes = old["resource_hashes"]
|
|
163
|
+
for svc in new_services & old_services: # Intersection - services in both
|
|
164
|
+
old_hash = old_hashes.get(svc)
|
|
165
|
+
new_hash = compute_resource_hash(svc)
|
|
166
|
+
if old_hash and new_hash and old_hash != new_hash:
|
|
167
|
+
modified.add(svc)
|
|
168
|
+
|
|
169
|
+
return added, removed, modified
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def get_current_services(scan_root: str = "services/product") -> List[str]:
|
|
173
|
+
"""
|
|
174
|
+
Scan filesystem for current service.json files.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
scan_root: Root directory to scan
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
List of service.json file paths
|
|
181
|
+
"""
|
|
182
|
+
import subprocess
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
result = subprocess.run(
|
|
186
|
+
["find", scan_root, "-type", "f", "-name", "service.json"],
|
|
187
|
+
capture_output=True,
|
|
188
|
+
text=True,
|
|
189
|
+
timeout=5
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
if result.returncode == 0:
|
|
193
|
+
services = [line.strip() for line in result.stdout.split('\n') if line.strip()]
|
|
194
|
+
return sorted(services)
|
|
195
|
+
except subprocess.TimeoutExpired:
|
|
196
|
+
logger.warning(f"Service scan timed out for {scan_root}")
|
|
197
|
+
except subprocess.SubprocessError as e:
|
|
198
|
+
logger.warning(f"Service scan failed for {scan_root}: {e}")
|
|
199
|
+
|
|
200
|
+
return []
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def main():
|
|
204
|
+
"""CLI interface for snapshot operations."""
|
|
205
|
+
if len(sys.argv) < 2:
|
|
206
|
+
print("Usage: resource_snapshot.py <command> [args]")
|
|
207
|
+
print("Commands:")
|
|
208
|
+
print(" save - Save current service snapshot")
|
|
209
|
+
print(" load - Load and display snapshot")
|
|
210
|
+
print(" diff - Compare current state with snapshot (uses hash-based comparison)")
|
|
211
|
+
print(" scan - Scan for services without saving")
|
|
212
|
+
print(" profile - Profile performance and resource usage (Task 10.5)")
|
|
213
|
+
print(" watch [interval] - Continuous monitoring with hash-based change detection")
|
|
214
|
+
print()
|
|
215
|
+
print("Examples:")
|
|
216
|
+
print(" python3 resource_snapshot.py scan")
|
|
217
|
+
print(" python3 resource_snapshot.py diff")
|
|
218
|
+
print(" python3 resource_snapshot.py profile")
|
|
219
|
+
print(" python3 resource_snapshot.py watch 5")
|
|
220
|
+
return
|
|
221
|
+
|
|
222
|
+
command = sys.argv[1]
|
|
223
|
+
|
|
224
|
+
if command == "save":
|
|
225
|
+
services = get_current_services()
|
|
226
|
+
save_snapshot(services)
|
|
227
|
+
print(f"✅ Snapshot saved: {len(services)} services")
|
|
228
|
+
|
|
229
|
+
elif command == "load":
|
|
230
|
+
snapshot = load_snapshot()
|
|
231
|
+
print(json.dumps(snapshot, indent=2))
|
|
232
|
+
|
|
233
|
+
elif command == "diff":
|
|
234
|
+
import time
|
|
235
|
+
start = time.time()
|
|
236
|
+
|
|
237
|
+
old = load_snapshot()
|
|
238
|
+
new = get_current_services()
|
|
239
|
+
added, removed, modified = diff_snapshots(old, new, use_hashes=True)
|
|
240
|
+
|
|
241
|
+
elapsed = (time.time() - start) * 1000 # Convert to ms
|
|
242
|
+
|
|
243
|
+
print(f"📊 Snapshot diff (computed in {elapsed:.1f}ms):")
|
|
244
|
+
print(f" Previous: {old.get('count', 0)} services")
|
|
245
|
+
print(f" Current: {len(new)} services")
|
|
246
|
+
print(f" Added: {len(added)}")
|
|
247
|
+
print(f" Removed: {len(removed)}")
|
|
248
|
+
print(f" Modified: {len(modified)}")
|
|
249
|
+
|
|
250
|
+
if added:
|
|
251
|
+
print("\n New services:")
|
|
252
|
+
for svc in sorted(added):
|
|
253
|
+
print(f" + {svc}")
|
|
254
|
+
|
|
255
|
+
if removed:
|
|
256
|
+
print("\n Removed services:")
|
|
257
|
+
for svc in sorted(removed):
|
|
258
|
+
print(f" - {svc}")
|
|
259
|
+
|
|
260
|
+
if modified:
|
|
261
|
+
print("\n Modified services (content changed):")
|
|
262
|
+
for svc in sorted(modified):
|
|
263
|
+
print(f" ~ {svc}")
|
|
264
|
+
|
|
265
|
+
print(f"\n ⚡ Hash-based comparison: enabled")
|
|
266
|
+
if old.get('hash'):
|
|
267
|
+
print(f" 🔐 Aggregate hash: {old['hash'][:8]}...")
|
|
268
|
+
|
|
269
|
+
elif command == "scan":
|
|
270
|
+
services = get_current_services()
|
|
271
|
+
print(f"🔍 Found {len(services)} services:")
|
|
272
|
+
for svc in services:
|
|
273
|
+
print(f" - {svc}")
|
|
274
|
+
|
|
275
|
+
elif command == "profile":
|
|
276
|
+
"""Profile resource usage and performance metrics."""
|
|
277
|
+
import time
|
|
278
|
+
import resource
|
|
279
|
+
|
|
280
|
+
print("🔬 Profiling snapshot operations...")
|
|
281
|
+
print()
|
|
282
|
+
|
|
283
|
+
# Memory baseline
|
|
284
|
+
baseline_mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024 # KB to MB
|
|
285
|
+
|
|
286
|
+
# Time the scan operation
|
|
287
|
+
start = time.time()
|
|
288
|
+
services = get_current_services()
|
|
289
|
+
scan_time = (time.time() - start) * 1000
|
|
290
|
+
|
|
291
|
+
# Time hash computation
|
|
292
|
+
start = time.time()
|
|
293
|
+
if services:
|
|
294
|
+
svc_hash = compute_services_hash(services)
|
|
295
|
+
hash_time = (time.time() - start) * 1000 if services else 0
|
|
296
|
+
|
|
297
|
+
# Time snapshot save
|
|
298
|
+
start = time.time()
|
|
299
|
+
save_snapshot(services, include_hashes=True)
|
|
300
|
+
save_time = (time.time() - start) * 1000
|
|
301
|
+
|
|
302
|
+
# Memory after operations
|
|
303
|
+
final_mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024
|
|
304
|
+
memory_used = final_mem - baseline_mem
|
|
305
|
+
|
|
306
|
+
print("📊 Performance Profile:")
|
|
307
|
+
print(f" Services scanned: {len(services)}")
|
|
308
|
+
print(f" Scan time: {scan_time:.2f}ms")
|
|
309
|
+
print(f" Hash computation: {hash_time:.2f}ms")
|
|
310
|
+
print(f" Snapshot save: {save_time:.2f}ms")
|
|
311
|
+
print(f" Total time: {scan_time + hash_time + save_time:.2f}ms")
|
|
312
|
+
print(f" Memory used: {memory_used:.2f} MB")
|
|
313
|
+
print()
|
|
314
|
+
|
|
315
|
+
# Performance targets
|
|
316
|
+
print("🎯 Performance Targets:")
|
|
317
|
+
print(f" Scan < 500ms: {'✅ PASS' if scan_time < 500 else '⚠️ FAIL'}")
|
|
318
|
+
print(f" Memory < 10MB: {'✅ PASS' if memory_used < 10 else '⚠️ FAIL'}")
|
|
319
|
+
print()
|
|
320
|
+
|
|
321
|
+
if services:
|
|
322
|
+
print(f"🔐 Aggregate hash: {svc_hash[:16]}...")
|
|
323
|
+
|
|
324
|
+
elif command == "watch":
|
|
325
|
+
"""Continuous monitoring mode for daemon operation."""
|
|
326
|
+
import time
|
|
327
|
+
|
|
328
|
+
scan_interval = int(sys.argv[2]) if len(sys.argv) > 2 else 5
|
|
329
|
+
|
|
330
|
+
print(f"👁️ Starting continuous monitoring (interval: {scan_interval}s)")
|
|
331
|
+
print(" Press Ctrl+C to stop")
|
|
332
|
+
print()
|
|
333
|
+
|
|
334
|
+
# Initialize snapshot if needed
|
|
335
|
+
if not SNAPSHOT_FILE.exists():
|
|
336
|
+
services = get_current_services()
|
|
337
|
+
save_snapshot(services)
|
|
338
|
+
print(f"✅ Initial snapshot: {len(services)} services")
|
|
339
|
+
|
|
340
|
+
try:
|
|
341
|
+
while True:
|
|
342
|
+
old = load_snapshot()
|
|
343
|
+
current = get_current_services()
|
|
344
|
+
added, removed, modified = diff_snapshots(old, current, use_hashes=True)
|
|
345
|
+
|
|
346
|
+
if added or removed or modified:
|
|
347
|
+
print(f"🔍 Changes detected at {datetime.now(timezone.utc).strftime('%H:%M:%S')}:")
|
|
348
|
+
if added:
|
|
349
|
+
print(f" + {len(added)} new service(s)")
|
|
350
|
+
for svc in added:
|
|
351
|
+
print(f" + {svc}")
|
|
352
|
+
if removed:
|
|
353
|
+
print(f" - {len(removed)} removed service(s)")
|
|
354
|
+
for svc in removed:
|
|
355
|
+
print(f" - {svc}")
|
|
356
|
+
if modified:
|
|
357
|
+
print(f" ~ {len(modified)} modified service(s)")
|
|
358
|
+
for svc in modified:
|
|
359
|
+
print(f" ~ {svc}")
|
|
360
|
+
|
|
361
|
+
# Update snapshot
|
|
362
|
+
save_snapshot(current)
|
|
363
|
+
print(f"✅ Snapshot updated: {len(current)} services")
|
|
364
|
+
|
|
365
|
+
time.sleep(scan_interval)
|
|
366
|
+
|
|
367
|
+
except KeyboardInterrupt:
|
|
368
|
+
print("\n👋 Monitoring stopped")
|
|
369
|
+
|
|
370
|
+
else:
|
|
371
|
+
print(f"Unknown command: {command}")
|
|
372
|
+
print("\nAvailable commands:")
|
|
373
|
+
print(" save - Save current snapshot")
|
|
374
|
+
print(" load - Load and display snapshot")
|
|
375
|
+
print(" diff - Compare current state with snapshot")
|
|
376
|
+
print(" scan - Scan for services without saving")
|
|
377
|
+
print(" profile - Profile performance and resource usage")
|
|
378
|
+
print(" watch [N] - Continuous monitoring with N-second interval (default: 5)")
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
if __name__ == "__main__":
|
|
382
|
+
main()
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# 📸 RESOURCE SNAPSHOT - Starlark Interface
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Provides Starlark functions for snapshot-based incremental resource discovery
|
|
5
|
+
# =============================================================================
|
|
6
|
+
|
|
7
|
+
# Python script path (relative to Tiltfile)
|
|
8
|
+
_SNAPSHOT_SCRIPT = ".tdk/.tdk-out/snapshots/resource_snapshot.py"
|
|
9
|
+
|
|
10
|
+
def _run_snapshot_command(cmd):
|
|
11
|
+
"""Run a snapshot command via Python script."""
|
|
12
|
+
result = local(
|
|
13
|
+
"python3 " + _SNAPSHOT_SCRIPT + " " + cmd,
|
|
14
|
+
quiet=True,
|
|
15
|
+
echo_off=True
|
|
16
|
+
)
|
|
17
|
+
return str(result)
|
|
18
|
+
|
|
19
|
+
def save_snapshot(resources):
|
|
20
|
+
"""
|
|
21
|
+
Save current resource list to snapshot file.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
resources: List of service.json file paths
|
|
25
|
+
"""
|
|
26
|
+
# Use Python to save snapshot directly
|
|
27
|
+
result = local(
|
|
28
|
+
"cd " + config.main_dir + " && python3 " + _SNAPSHOT_SCRIPT + " save",
|
|
29
|
+
quiet=True,
|
|
30
|
+
echo_off=True
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
return str(result)
|
|
34
|
+
|
|
35
|
+
def load_from_file():
|
|
36
|
+
"""
|
|
37
|
+
Load previous snapshot from file.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Dict with 'timestamp', 'resources', 'count'
|
|
41
|
+
"""
|
|
42
|
+
result = _run_snapshot_command("load")
|
|
43
|
+
|
|
44
|
+
# Parse JSON result
|
|
45
|
+
if result and result.strip():
|
|
46
|
+
# In Starlark, we can't use try/except, so we just try to decode
|
|
47
|
+
parsed = decode_json(result)
|
|
48
|
+
if parsed:
|
|
49
|
+
return parsed
|
|
50
|
+
|
|
51
|
+
# Return empty snapshot on error
|
|
52
|
+
return {
|
|
53
|
+
"timestamp": None,
|
|
54
|
+
"services": [],
|
|
55
|
+
"count": 0
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
def diff_snapshots(old_snapshot, current_resources):
|
|
59
|
+
"""
|
|
60
|
+
Compare old snapshot with current resources.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
old_snapshot: Previous snapshot dict
|
|
64
|
+
current_resources: Current list of resource paths
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Struct with 'added' and 'removed' lists
|
|
68
|
+
"""
|
|
69
|
+
old_set = {}
|
|
70
|
+
for resource in old_snapshot.get("resources", []):
|
|
71
|
+
old_set[resource] = True
|
|
72
|
+
|
|
73
|
+
current_set = {}
|
|
74
|
+
for resource in current_resources:
|
|
75
|
+
current_set[resource] = True
|
|
76
|
+
|
|
77
|
+
# Find added resources
|
|
78
|
+
added = []
|
|
79
|
+
for resource in current_resources:
|
|
80
|
+
if resource not in old_set:
|
|
81
|
+
added.append(resource)
|
|
82
|
+
|
|
83
|
+
# Find removed resources
|
|
84
|
+
removed = []
|
|
85
|
+
for resource in old_snapshot.get("resources", []):
|
|
86
|
+
if resource not in current_set:
|
|
87
|
+
removed.append(resource)
|
|
88
|
+
|
|
89
|
+
return struct(
|
|
90
|
+
added=added,
|
|
91
|
+
removed=removed,
|
|
92
|
+
added_count=len(added),
|
|
93
|
+
removed_count=len(removed)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def get_current_resources(scan_roots=["services/product"]):
|
|
97
|
+
"""
|
|
98
|
+
Scan filesystem for current service.json files.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
scan_roots: List of root directories to scan
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
List of service.json file paths (relative to project root)
|
|
105
|
+
"""
|
|
106
|
+
all_resources = []
|
|
107
|
+
|
|
108
|
+
for root in scan_roots:
|
|
109
|
+
# Use find command to locate service.json files
|
|
110
|
+
cmd = "find " + root + " -type f -name 'service.json' 2>/dev/null | sort"
|
|
111
|
+
result = local(cmd, quiet=True, echo_off=True)
|
|
112
|
+
|
|
113
|
+
if result:
|
|
114
|
+
lines = str(result).strip().split("\n")
|
|
115
|
+
for line in lines:
|
|
116
|
+
line = line.strip()
|
|
117
|
+
if line:
|
|
118
|
+
all_resources.append(line)
|
|
119
|
+
|
|
120
|
+
return all_resources
|
|
121
|
+
|
|
122
|
+
def snapshot_exists():
|
|
123
|
+
"""Check if snapshot file exists."""
|
|
124
|
+
result = local(
|
|
125
|
+
"test -f .tdk/.tdk-out/snapshots/resource-snapshot.json && echo 'yes' || echo 'no'",
|
|
126
|
+
quiet=True,
|
|
127
|
+
echo_off=True
|
|
128
|
+
)
|
|
129
|
+
return str(result).strip() == "yes"
|
|
130
|
+
|
|
131
|
+
# Get the path to the resource snapshot file
|
|
132
|
+
def get_resource_snapshot_path():
|
|
133
|
+
"""Return the path to the resource snapshot JSON file."""
|
|
134
|
+
return ".tdk/.tdk-out/snapshots/resource-snapshot.json"
|
|
135
|
+
|
|
136
|
+
# Export public API
|
|
137
|
+
ResourceSnapshot = struct(
|
|
138
|
+
save=save_snapshot,
|
|
139
|
+
load_from_file=load_from_file,
|
|
140
|
+
diff=diff_snapshots,
|
|
141
|
+
scan=get_current_resources,
|
|
142
|
+
exists=snapshot_exists,
|
|
143
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MANIFEST_SCHEMA_PATH = ".tilt/schemas/manifest-schema.json"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
appName: orchestrator-glue-backend
|
|
2
|
+
appType: backend
|
|
3
|
+
stack: platform
|
|
4
|
+
port: 5001
|
|
5
|
+
databaseName: beauty_crm_orchestrator
|
|
6
|
+
features:
|
|
7
|
+
- nats
|
|
8
|
+
- prisma
|
|
9
|
+
healthCheck:
|
|
10
|
+
port: 5001
|
|
11
|
+
interval: 30
|
|
12
|
+
path: /health
|
|
13
|
+
infisicalSecretPath: /services/orchestrator-glue
|
|
14
|
+
dependsOn:
|
|
15
|
+
replicas: 1
|
|
16
|
+
resources:
|
|
17
|
+
limits:
|
|
18
|
+
cpu: 500m
|
|
19
|
+
memory: 512Mi
|
|
20
|
+
requests:
|
|
21
|
+
cpu: 100m
|
|
22
|
+
memory: 256Mi
|
|
23
|
+
runtime: bun
|
|
24
|
+
traefik:
|
|
25
|
+
host: orchestrator.backend.beauty.local
|
|
26
|
+
pathPrefix: /api/orchestrator
|