@tdk-landscape/tdk-cli-core 1.3.14 → 1.3.22
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/README.md +3 -3
- 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 +62 -21
- 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/paths.js +1 -1
- package/dist/utils/paths.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,298 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Shared file utilities for Tilt IDE components
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional, List, Tuple
|
|
10
|
+
|
|
11
|
+
# TDK CLI root directory (5 levels up from this file: ext/ide-components/shared/)
|
|
12
|
+
PROJECT_ROOT = Path(__file__).parent.parent.parent.parent.parent
|
|
13
|
+
MAX_FILE_SIZE = 1024 * 1024 # 1MB
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class FileUtils:
|
|
17
|
+
"""Safe file operations for IDE components"""
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def validate_path(path: str) -> Optional[Path]:
|
|
21
|
+
"""
|
|
22
|
+
Validate and sanitize a file path.
|
|
23
|
+
Returns absolute Path if valid, None if invalid.
|
|
24
|
+
|
|
25
|
+
Security: Prevents path traversal attacks by ensuring
|
|
26
|
+
the resolved path is within the project root.
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
# Handle relative paths
|
|
30
|
+
if not path.startswith('/'):
|
|
31
|
+
target = PROJECT_ROOT / path
|
|
32
|
+
else:
|
|
33
|
+
target = Path(path)
|
|
34
|
+
|
|
35
|
+
# Resolve to absolute, removing .. and symlinks
|
|
36
|
+
resolved = target.resolve()
|
|
37
|
+
|
|
38
|
+
# Ensure within project root
|
|
39
|
+
try:
|
|
40
|
+
resolved.relative_to(PROJECT_ROOT.resolve())
|
|
41
|
+
except ValueError:
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
return resolved
|
|
45
|
+
except (ValueError, OSError, RuntimeError):
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def get_file_info(file_path: Path) -> dict:
|
|
50
|
+
"""Get file metadata for display"""
|
|
51
|
+
stat = file_path.stat()
|
|
52
|
+
size = stat.st_size
|
|
53
|
+
|
|
54
|
+
# Human-readable size
|
|
55
|
+
if size < 1024:
|
|
56
|
+
size_str = f"{size} B"
|
|
57
|
+
elif size < 1024 * 1024:
|
|
58
|
+
size_str = f"{size / 1024:.1f} KB"
|
|
59
|
+
else:
|
|
60
|
+
size_str = f"{size / (1024 * 1024):.1f} MB"
|
|
61
|
+
|
|
62
|
+
# Modified time
|
|
63
|
+
from datetime import datetime
|
|
64
|
+
mtime = datetime.fromtimestamp(stat.st_mtime)
|
|
65
|
+
mtime_str = mtime.strftime("%Y-%m-%d %H:%M")
|
|
66
|
+
|
|
67
|
+
# File type icon
|
|
68
|
+
ext = file_path.suffix.lower()
|
|
69
|
+
icon = FileUtils.get_file_icon(ext, file_path.is_dir(), file_path.name)
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
'name': file_path.name,
|
|
73
|
+
'path': str(file_path.relative_to(PROJECT_ROOT)),
|
|
74
|
+
'size': size,
|
|
75
|
+
'size_str': size_str,
|
|
76
|
+
'modified': mtime_str,
|
|
77
|
+
'is_dir': file_path.is_dir(),
|
|
78
|
+
'icon': icon,
|
|
79
|
+
'extension': ext,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def get_file_icon(ext: str, is_dir: bool, filename: str = '') -> str:
|
|
84
|
+
"""Get emoji icon for file type"""
|
|
85
|
+
if is_dir:
|
|
86
|
+
if filename.startswith('.'):
|
|
87
|
+
return '🔒'
|
|
88
|
+
if filename in ('node_modules', 'vendor', '__pycache__'):
|
|
89
|
+
return '📦'
|
|
90
|
+
return '📁'
|
|
91
|
+
|
|
92
|
+
# Check special filenames first (exact match)
|
|
93
|
+
special_icons = {
|
|
94
|
+
'Makefile': '🔨',
|
|
95
|
+
'README': '📖',
|
|
96
|
+
'LICENSE': '📜',
|
|
97
|
+
'Dockerfile': '🐳',
|
|
98
|
+
'docker-compose.yml': '🐳',
|
|
99
|
+
'docker-compose.yaml': '🐳',
|
|
100
|
+
'.gitignore': '🚫',
|
|
101
|
+
'go.mod': '🔵',
|
|
102
|
+
'go.sum': '🔵',
|
|
103
|
+
'Cargo.toml': '🦀',
|
|
104
|
+
'Cargo.lock': '🦀',
|
|
105
|
+
'package.json': '⬡',
|
|
106
|
+
'package-lock.json': '⬡',
|
|
107
|
+
'requirements.txt': '🐍',
|
|
108
|
+
'setup.py': '🐍',
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if filename in special_icons:
|
|
112
|
+
return special_icons[filename]
|
|
113
|
+
|
|
114
|
+
icons = {
|
|
115
|
+
'.ts': '📘', '.tsx': '📘',
|
|
116
|
+
'.js': '📒', '.jsx': '📒',
|
|
117
|
+
'.mjs': '📒', '.cjs': '📒',
|
|
118
|
+
'.json': '📋',
|
|
119
|
+
'.yaml': '📋', '.yml': '📋',
|
|
120
|
+
'.star': '⭐',
|
|
121
|
+
'.py': '🐍',
|
|
122
|
+
'.pyc': '🐍',
|
|
123
|
+
'.pyo': '🐍',
|
|
124
|
+
'.ipynb': '📓',
|
|
125
|
+
'.md': '📝',
|
|
126
|
+
'.mdx': '📝',
|
|
127
|
+
'.txt': '📄',
|
|
128
|
+
'.prisma': '🗃️',
|
|
129
|
+
'.dockerfile': '🐳', '.docker': '🐳',
|
|
130
|
+
'.sh': '🔧',
|
|
131
|
+
'.bash': '🔧',
|
|
132
|
+
'.zsh': '🔧',
|
|
133
|
+
'.fish': '🔧',
|
|
134
|
+
'.css': '🎨', '.scss': '🎨', '.sass': '🎨', '.less': '🎨',
|
|
135
|
+
'.html': '🌐', '.htm': '🌐', '.xhtml': '🌐',
|
|
136
|
+
'.vue': '💚',
|
|
137
|
+
'.svelte': '🧡',
|
|
138
|
+
'.conf': '⚙️', '.config': '⚙️', '.cfg': '⚙️',
|
|
139
|
+
'.ini': '⚙️',
|
|
140
|
+
'.toml': '⚙️',
|
|
141
|
+
'.env': '🔐',
|
|
142
|
+
'.env.local': '🔐', '.env.production': '🔐', '.env.development': '🔐',
|
|
143
|
+
'.sql': '🗄️',
|
|
144
|
+
'.go': '🔵',
|
|
145
|
+
'.rs': '🦀',
|
|
146
|
+
'.java': '☕',
|
|
147
|
+
'.class': '☕',
|
|
148
|
+
'.jar': '☕',
|
|
149
|
+
'.kt': '💜',
|
|
150
|
+
'.swift': '🦅',
|
|
151
|
+
'.rb': '💎',
|
|
152
|
+
'.php': '🐘',
|
|
153
|
+
'.c': '🇨',
|
|
154
|
+
'.cpp': '🇨🇵',
|
|
155
|
+
'.cc': '🇨🇵',
|
|
156
|
+
'.h': '📋',
|
|
157
|
+
'.hpp': '📋',
|
|
158
|
+
'.zig': '⚡',
|
|
159
|
+
'.lua': '🌙',
|
|
160
|
+
'.r': '📊',
|
|
161
|
+
'.R': '📊',
|
|
162
|
+
'.lock': '🔒',
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return icons.get(ext, '📄')
|
|
166
|
+
|
|
167
|
+
@staticmethod
|
|
168
|
+
def read_file_safe(file_path: str, max_size: int = MAX_FILE_SIZE) -> Tuple[Optional[str], Optional[str]]:
|
|
169
|
+
"""
|
|
170
|
+
Safely read a file with size limit.
|
|
171
|
+
|
|
172
|
+
Returns: (content, error_message)
|
|
173
|
+
- If success: (content, None)
|
|
174
|
+
- If error: (None, error_message)
|
|
175
|
+
"""
|
|
176
|
+
resolved = FileUtils.validate_path(file_path)
|
|
177
|
+
|
|
178
|
+
if not resolved:
|
|
179
|
+
return None, "Invalid path or access denied"
|
|
180
|
+
|
|
181
|
+
if not resolved.exists():
|
|
182
|
+
return None, f"File not found: {file_path}"
|
|
183
|
+
|
|
184
|
+
if resolved.is_dir():
|
|
185
|
+
return None, "Path is a directory, not a file"
|
|
186
|
+
|
|
187
|
+
# Check size
|
|
188
|
+
size = resolved.stat().st_size
|
|
189
|
+
if size > max_size:
|
|
190
|
+
return None, f"File too large ({size / (1024*1024):.1f} MB > {max_size / (1024*1024):.1f} MB limit)"
|
|
191
|
+
|
|
192
|
+
try:
|
|
193
|
+
with open(resolved, 'r', encoding='utf-8', errors='replace') as f:
|
|
194
|
+
return f.read(), None
|
|
195
|
+
except Exception as e:
|
|
196
|
+
return None, f"Error reading file: {str(e)}"
|
|
197
|
+
|
|
198
|
+
@staticmethod
|
|
199
|
+
def list_directory(dir_path: str) -> Tuple[Optional[List[dict]], Optional[str]]:
|
|
200
|
+
"""
|
|
201
|
+
List directory contents safely.
|
|
202
|
+
|
|
203
|
+
Returns: (items, error_message)
|
|
204
|
+
"""
|
|
205
|
+
resolved = FileUtils.validate_path(dir_path)
|
|
206
|
+
|
|
207
|
+
if not resolved:
|
|
208
|
+
return None, "Invalid path or access denied"
|
|
209
|
+
|
|
210
|
+
if not resolved.exists():
|
|
211
|
+
return None, f"Directory not found: {dir_path}"
|
|
212
|
+
|
|
213
|
+
if not resolved.is_dir():
|
|
214
|
+
return None, "Path is not a directory"
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
items = []
|
|
218
|
+
for entry in sorted(resolved.iterdir()):
|
|
219
|
+
# Skip hidden files
|
|
220
|
+
if entry.name.startswith('.'):
|
|
221
|
+
continue
|
|
222
|
+
items.append(FileUtils.get_file_info(entry))
|
|
223
|
+
return items, None
|
|
224
|
+
except Exception as e:
|
|
225
|
+
return None, f"Error reading directory: {str(e)}"
|
|
226
|
+
|
|
227
|
+
@staticmethod
|
|
228
|
+
def search_files(query: str, max_results: int = 50) -> List[dict]:
|
|
229
|
+
"""
|
|
230
|
+
Search for files by name across the project.
|
|
231
|
+
|
|
232
|
+
Returns list of matching file info dicts.
|
|
233
|
+
"""
|
|
234
|
+
results = []
|
|
235
|
+
query_lower = query.lower()
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
for root, dirs, files in os.walk(PROJECT_ROOT):
|
|
239
|
+
# Skip hidden directories and common ignores
|
|
240
|
+
dirs[:] = [d for d in dirs if not d.startswith('.') and
|
|
241
|
+
d not in ('node_modules', 'dist', 'build', '.git', '__pycache__', 'coverage')]
|
|
242
|
+
|
|
243
|
+
for name in files:
|
|
244
|
+
if query_lower in name.lower():
|
|
245
|
+
file_path = Path(root) / name
|
|
246
|
+
try:
|
|
247
|
+
info = FileUtils.get_file_info(file_path)
|
|
248
|
+
results.append(info)
|
|
249
|
+
if len(results) >= max_results:
|
|
250
|
+
return results
|
|
251
|
+
except (OSError, PermissionError):
|
|
252
|
+
continue
|
|
253
|
+
|
|
254
|
+
except Exception:
|
|
255
|
+
pass
|
|
256
|
+
|
|
257
|
+
return results
|
|
258
|
+
|
|
259
|
+
@staticmethod
|
|
260
|
+
def get_language_from_ext(ext: str) -> str:
|
|
261
|
+
"""Get language identifier from file extension"""
|
|
262
|
+
languages = {
|
|
263
|
+
'.ts': 'typescript', '.tsx': 'typescript',
|
|
264
|
+
'.js': 'javascript', '.jsx': 'javascript',
|
|
265
|
+
'.json': 'json',
|
|
266
|
+
'.yaml': 'yaml', '.yml': 'yaml',
|
|
267
|
+
'.star': 'python', # Starlark is Python-like
|
|
268
|
+
'.py': 'python',
|
|
269
|
+
'.md': 'markdown',
|
|
270
|
+
'.prisma': 'prisma',
|
|
271
|
+
'.dockerfile': 'dockerfile',
|
|
272
|
+
'.sh': 'bash',
|
|
273
|
+
'.css': 'css', '.scss': 'scss', '.less': 'less',
|
|
274
|
+
'.html': 'html', '.htm': 'html',
|
|
275
|
+
'.sql': 'sql',
|
|
276
|
+
'.go': 'go',
|
|
277
|
+
'.rs': 'rust',
|
|
278
|
+
'.java': 'java',
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return languages.get(ext, 'text')
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
if __name__ == '__main__':
|
|
285
|
+
# Quick test
|
|
286
|
+
print(f"Project root: {PROJECT_ROOT}")
|
|
287
|
+
|
|
288
|
+
# Test validate_path
|
|
289
|
+
test_paths = [
|
|
290
|
+
'.',
|
|
291
|
+
'services/product/staff',
|
|
292
|
+
'../outside', # Should fail
|
|
293
|
+
'/etc/passwd', # Should fail
|
|
294
|
+
]
|
|
295
|
+
|
|
296
|
+
for path in test_paths:
|
|
297
|
+
result = FileUtils.validate_path(path)
|
|
298
|
+
print(f"Path '{path}': {result}")
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Shared HTTP handler utilities for Tilt IDE components.
|
|
4
|
+
Provides a base handler class with common HTTP functionality.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from http.server import BaseHTTPRequestHandler
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseIDEHandler(BaseHTTPRequestHandler):
|
|
14
|
+
"""
|
|
15
|
+
Base HTTP handler for Tilt IDE components.
|
|
16
|
+
|
|
17
|
+
Provides common functionality:
|
|
18
|
+
- JSON/HTML response helpers
|
|
19
|
+
- HTML escaping for XSS prevention
|
|
20
|
+
- Page rendering with shared template
|
|
21
|
+
- Suppressed logging
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# Shared template fallback (used when base.html is not found)
|
|
25
|
+
DEFAULT_TEMPLATE = '''<!DOCTYPE html>
|
|
26
|
+
<html lang="en">
|
|
27
|
+
<head>
|
|
28
|
+
<meta charset="UTF-8">
|
|
29
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
30
|
+
<title>{title}</title>
|
|
31
|
+
<link rel="stylesheet" href="/static/styles.css">
|
|
32
|
+
</head>
|
|
33
|
+
<body>
|
|
34
|
+
<header class="header">
|
|
35
|
+
<h1>{icon} {title}</h1>
|
|
36
|
+
{controls}
|
|
37
|
+
</header>
|
|
38
|
+
<div class="container">
|
|
39
|
+
{sidebar}
|
|
40
|
+
<main class="content">{content}</main>
|
|
41
|
+
</div>
|
|
42
|
+
{scripts}
|
|
43
|
+
</body>
|
|
44
|
+
</html>'''
|
|
45
|
+
|
|
46
|
+
def log_message(self, format, *args):
|
|
47
|
+
"""Suppress default request logging."""
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
def send_json_response(self, data: dict, status: int = 200) -> None:
|
|
51
|
+
"""
|
|
52
|
+
Send a JSON response with CORS headers.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
data: Response data to serialize as JSON
|
|
56
|
+
status: HTTP status code (default: 200)
|
|
57
|
+
"""
|
|
58
|
+
self.send_response(status)
|
|
59
|
+
self.send_header('Content-Type', 'application/json')
|
|
60
|
+
self.send_header('Access-Control-Allow-Origin', '*')
|
|
61
|
+
self.end_headers()
|
|
62
|
+
self.wfile.write(json.dumps(data).encode())
|
|
63
|
+
|
|
64
|
+
def send_html_response(self, html: str, status: int = 200) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Send an HTML response with CORS headers.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
html: HTML content to send
|
|
70
|
+
status: HTTP status code (default: 200)
|
|
71
|
+
"""
|
|
72
|
+
self.send_response(status)
|
|
73
|
+
self.send_header('Content-Type', 'text/html; charset=utf-8')
|
|
74
|
+
self.send_header('Access-Control-Allow-Origin', '*')
|
|
75
|
+
self.end_headers()
|
|
76
|
+
self.wfile.write(html.encode())
|
|
77
|
+
|
|
78
|
+
def send_css_response(self, css: str) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Send a CSS response.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
css: CSS content to send
|
|
84
|
+
"""
|
|
85
|
+
self.send_response(200)
|
|
86
|
+
self.send_header('Content-Type', 'text/css')
|
|
87
|
+
self.end_headers()
|
|
88
|
+
self.wfile.write(css.encode())
|
|
89
|
+
|
|
90
|
+
def send_error_response(self, status: int, message: str) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Send an error response.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
status: HTTP status code
|
|
96
|
+
message: Error message
|
|
97
|
+
"""
|
|
98
|
+
self.send_response(status)
|
|
99
|
+
self.send_header('Content-Type', 'text/plain')
|
|
100
|
+
self.end_headers()
|
|
101
|
+
self.wfile.write(message.encode())
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def escape_html(text: str) -> str:
|
|
105
|
+
"""
|
|
106
|
+
Escape HTML special characters to prevent XSS attacks.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
text: Raw text to escape
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Escaped text safe for HTML insertion
|
|
113
|
+
"""
|
|
114
|
+
return (text
|
|
115
|
+
.replace('&', '&')
|
|
116
|
+
.replace('<', '<')
|
|
117
|
+
.replace('>', '>')
|
|
118
|
+
.replace('"', '"')
|
|
119
|
+
.replace("'", '''))
|
|
120
|
+
|
|
121
|
+
def render_page(
|
|
122
|
+
self,
|
|
123
|
+
title: str,
|
|
124
|
+
content: str,
|
|
125
|
+
icon: str = '📄',
|
|
126
|
+
sidebar: str = '',
|
|
127
|
+
controls: str = '',
|
|
128
|
+
scripts: str = ''
|
|
129
|
+
) -> str:
|
|
130
|
+
"""
|
|
131
|
+
Render a full HTML page using the base template.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
title: Page title
|
|
135
|
+
content: Main content HTML
|
|
136
|
+
icon: Emoji icon for the page header
|
|
137
|
+
sidebar: Sidebar HTML (optional)
|
|
138
|
+
controls: Header controls HTML (optional)
|
|
139
|
+
scripts: Scripts to include before </body> (optional)
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Complete HTML page as string
|
|
143
|
+
"""
|
|
144
|
+
# Try to load template from file
|
|
145
|
+
template = self._load_template()
|
|
146
|
+
|
|
147
|
+
# Build sidebar wrapper if content provided
|
|
148
|
+
sidebar_html = f'<aside class="sidebar">{sidebar}</aside>' if sidebar else ''
|
|
149
|
+
|
|
150
|
+
# Use string replacement to avoid conflicts with JS braces
|
|
151
|
+
result = template.replace('{title}', self.escape_html(title))
|
|
152
|
+
result = result.replace('{icon}', icon)
|
|
153
|
+
result = result.replace('{favicon}', icon)
|
|
154
|
+
result = result.replace('{controls}', controls)
|
|
155
|
+
result = result.replace('{sidebar}', sidebar_html)
|
|
156
|
+
result = result.replace('{content}', content)
|
|
157
|
+
result = result.replace('{scripts}', scripts)
|
|
158
|
+
|
|
159
|
+
return result
|
|
160
|
+
|
|
161
|
+
def _load_template(self) -> str:
|
|
162
|
+
"""Load base template from file or return default."""
|
|
163
|
+
try:
|
|
164
|
+
template_path = self._get_template_path()
|
|
165
|
+
if template_path and template_path.exists():
|
|
166
|
+
with open(template_path, 'r', encoding='utf-8') as f:
|
|
167
|
+
return f.read()
|
|
168
|
+
except Exception:
|
|
169
|
+
pass
|
|
170
|
+
return self.DEFAULT_TEMPLATE
|
|
171
|
+
|
|
172
|
+
def _get_template_path(self) -> Optional[Path]:
|
|
173
|
+
"""Get path to base template. Override in subclasses if needed."""
|
|
174
|
+
# Default: look in shared/templates/ relative to this file
|
|
175
|
+
shared_dir = Path(__file__).parent
|
|
176
|
+
return shared_dir / 'templates' / 'base.html'
|
|
177
|
+
|
|
178
|
+
def handle_health_check(self, service_name: str, features: Optional[list] = None) -> None:
|
|
179
|
+
"""
|
|
180
|
+
Handle a standard health check request.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
service_name: Name of the service for the response
|
|
184
|
+
features: Optional list of service features/capabilities
|
|
185
|
+
"""
|
|
186
|
+
response = {
|
|
187
|
+
'status': 'ok',
|
|
188
|
+
'service': service_name
|
|
189
|
+
}
|
|
190
|
+
if features:
|
|
191
|
+
response['features'] = features
|
|
192
|
+
self.send_json_response(response)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def run_server(server_class, port: int, service_name: str, service_description: str) -> None:
|
|
196
|
+
"""
|
|
197
|
+
Run an HTTP server with standard configuration.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
server_class: The HTTP handler class to use
|
|
201
|
+
port: Port number to listen on
|
|
202
|
+
service_name: Name of the service for startup message
|
|
203
|
+
service_description: Brief description of the service
|
|
204
|
+
"""
|
|
205
|
+
from http.server import HTTPServer
|
|
206
|
+
|
|
207
|
+
server = HTTPServer(('127.0.0.1', port), server_class)
|
|
208
|
+
print(f"{service_name} running at http://localhost:{port}")
|
|
209
|
+
if service_description:
|
|
210
|
+
print(f" {service_description}")
|
|
211
|
+
|
|
212
|
+
try:
|
|
213
|
+
server.serve_forever()
|
|
214
|
+
except KeyboardInterrupt:
|
|
215
|
+
print("\nShutting down...")
|
|
216
|
+
server.shutdown()
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
# Backwards compatibility: standalone functions that delegate to class methods
|
|
220
|
+
def send_json_response(handler: BaseHTTPRequestHandler, data: dict, status: int = 200) -> None:
|
|
221
|
+
"""Standalone function for sending JSON responses (legacy compatibility)."""
|
|
222
|
+
BaseIDEHandler.send_json_response(handler, data, status)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def send_html_response(handler: BaseHTTPRequestHandler, html: str, status: int = 200) -> None:
|
|
226
|
+
"""Standalone function for sending HTML responses (legacy compatibility)."""
|
|
227
|
+
BaseIDEHandler.send_html_response(handler, html, status)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def escape_html(text: str) -> str:
|
|
231
|
+
"""Standalone function for HTML escaping (legacy compatibility)."""
|
|
232
|
+
return BaseIDEHandler.escape_html(text)
|