@tdk-landscape/tdk-cli-core 1.3.51 → 1.3.53
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/.github/ISSUE_TEMPLATE/config.yml +3 -0
- package/.github/ISSUE_TEMPLATE/premium_license.yml +43 -0
- package/.github/workflows/ci.yml +13 -0
- package/.github/workflows/release-binaries.yml +76 -1
- package/CHANGELOG.md +55 -0
- package/README.md +52 -17
- package/cli/README.md +16 -43
- package/cli/biome.json +0 -4
- package/cli/dist/commands/config.js +1 -1
- package/cli/dist/commands/config.js.map +1 -1
- package/cli/dist/commands/help.d.ts.map +1 -1
- package/cli/dist/commands/help.js +22 -39
- package/cli/dist/commands/help.js.map +1 -1
- package/cli/dist/commands/project.d.ts +6 -0
- package/cli/dist/commands/project.d.ts.map +1 -1
- package/cli/dist/commands/project.js +16 -0
- package/cli/dist/commands/project.js.map +1 -1
- package/cli/dist/commands/resource.js +1 -1
- package/cli/dist/commands/resource.js.map +1 -1
- package/cli/dist/commands/up.d.ts.map +1 -1
- package/cli/dist/commands/up.js +5 -0
- package/cli/dist/commands/up.js.map +1 -1
- package/cli/dist/commands/upgrade.d.ts +3 -0
- package/cli/dist/commands/upgrade.d.ts.map +1 -1
- package/cli/dist/commands/upgrade.js +43 -1
- package/cli/dist/commands/upgrade.js.map +1 -1
- package/cli/dist/utils/constants.d.ts +1 -1
- package/cli/dist/utils/constants.d.ts.map +1 -1
- package/cli/dist/utils/constants.js +1 -1
- package/cli/dist/utils/constants.js.map +1 -1
- package/cli/dist/utils/doctor-runtime.js +5 -5
- package/cli/dist/utils/doctor-runtime.js.map +1 -1
- package/cli/dist/utils/prompt.d.ts.map +1 -1
- package/cli/dist/utils/prompt.js +6 -1
- package/cli/dist/utils/prompt.js.map +1 -1
- package/cli/dist/utils/service-urls.js +1 -1
- package/cli/dist/utils/service-urls.js.map +1 -1
- package/cli/package.json +2 -1
- package/cli/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +2 -2
- package/cli/src/commands/__tests__/doctor.test.ts +8 -8
- package/cli/src/commands/__tests__/upgrade.test.ts +90 -3
- package/cli/src/commands/config.ts +1 -1
- package/cli/src/commands/help.ts +22 -39
- package/cli/src/commands/project.ts +20 -0
- package/cli/src/commands/resource.ts +1 -1
- package/cli/src/commands/up.ts +10 -0
- package/cli/src/commands/upgrade.ts +52 -1
- package/cli/src/utils/constants.ts +1 -1
- package/cli/src/utils/doctor-runtime.ts +5 -5
- package/cli/src/utils/prompt.ts +8 -1
- package/cli/src/utils/service-urls.ts +1 -1
- package/discovery/identity-management-backend/service.yaml +2 -2
- package/discovery/identity-management-frontend/service.yaml +1 -1
- package/discovery/registry.star +3 -1
- package/discovery/services/platform/orchestrator/orchestrator-glue-backend/service.yaml +2 -2
- package/docs/FEATURES.md +2 -0
- package/engine/assets/docker/golden-layers.Dockerfile +18 -18
- package/engine/assets/docker/wake-gateway/decide.test.ts +25 -0
- package/engine/assets/docker/wake-gateway/decide.ts +19 -0
- package/engine/assets/docker/wake-gateway/server.ts +60 -14
- package/engine/assets/scripts/mac-m1-resource-monitor.sh +1 -1
- package/engine/scripts/debug-container.sh +8 -3
- package/engine/spec.master +2 -2
- package/engine/topologies/platform/docker/layers/prisma/prisma_build.star +1 -1
- package/engine/topologies/tilt/common/utils.star +1 -1
- package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +53 -11
- package/engine/topologies/tilt/resources/orchestrator/builders/typescript.star +20 -0
- package/install.sh +19 -242
- package/openspec/changes/prioritized-cold-start/design.md +5 -1
- package/openspec/changes/prioritized-cold-start/specs/on-demand-resource-startup/spec.md +9 -3
- package/openspec/changes/prioritized-cold-start/tasks.md +13 -0
- package/package.json +1 -1
- package/platform/services/platform/proxy/service.yaml +1 -1
- package/scripts/release-binaries.sh +8 -5
- package/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +2 -2
- package/tests/tilt-engine/test_sablier_defer_start.py +41 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/codebase-audit-report.md +0 -62
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/.openspec.yaml +0 -5
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/design.md +0 -94
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/proposal.md +0 -46
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CLEANUP_REPORT_8.md +0 -174
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CRITICAL_ASSESSMENT_8.md +0 -160
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/circular-deps/CRITICAL_ASSESSMENT_4.md +0 -381
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/dead-code/CRITICAL_ASSESSMENT_3.md +0 -316
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/CRITICAL_ASSESSMENT_1.md +0 -290
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/IMPLEMENTATION_SUMMARY_1.md +0 -233
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/defensive-cleanup/CRITICAL_ASSESSMENT_6.md +0 -835
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/CRITICAL_ASSESSMENT_7.md +0 -254
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/IMPLEMENTATION_SUMMARY_7.md +0 -187
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/strong-typing/CRITICAL_ASSESSMENT_5.md +0 -269
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/CRITICAL_ASSESSMENT_2.md +0 -312
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/IMPLEMENTATION_SUMMARY.md +0 -170
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/tasks.md +0 -137
package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star
CHANGED
|
@@ -244,7 +244,51 @@ def _wake_compose_invocation(project_root, resource_path, res_name, resource_nam
|
|
|
244
244
|
|
|
245
245
|
def _register_docker_build(config, live_update_rules):
|
|
246
246
|
"""Register docker_build with live_update for hot-reload support."""
|
|
247
|
-
|
|
247
|
+
TypescriptBuilders.build_typescript_service(
|
|
248
|
+
_app_image_name(config['resource_name'], config['res_name']),
|
|
249
|
+
config.get('project_root', '') or '.',
|
|
250
|
+
_resolve_dockerfile(config),
|
|
251
|
+
live_update_rules,
|
|
252
|
+
config['res_deps'],
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _register_deferred_image_prebuild(config, auto_init_apps):
|
|
257
|
+
"""Build a deferStart resource's image during `tdk up` without creating its container.
|
|
258
|
+
|
|
259
|
+
`auto_init=False` on the dc_resource skips its docker_build too (confirmed
|
|
260
|
+
live on tdk-erp-system, task 7.2), so a fresh project's first request would
|
|
261
|
+
find no image and the wake gateway would fall back to `tilt trigger`, which
|
|
262
|
+
queues behind every other build. This local_resource builds the same image
|
|
263
|
+
(same Dockerfile, `production` target, host network, and an allowlist
|
|
264
|
+
.dockerignore equivalent to docker_build's only=/ignore=) under the tag the
|
|
265
|
+
compose service declares, so the gateway can start it directly.
|
|
266
|
+
"""
|
|
267
|
+
project_root = config.get('project_root', '')
|
|
268
|
+
dockerfile = _resolve_dockerfile(config)
|
|
269
|
+
prebuild_dockerfile = dockerfile + '.prebuild'
|
|
270
|
+
ignore_content = TypescriptBuilders.prebuild_dockerignore(dockerfile, project_root, config['res_path'])
|
|
271
|
+
# BuildKit reads `<dockerfile>.dockerignore` for `-f <dockerfile>`; the
|
|
272
|
+
# original Dockerfile already has a (denylist) one, hence the copy.
|
|
273
|
+
cmd = (
|
|
274
|
+
"cp '" + dockerfile + "' '" + prebuild_dockerfile + "'"
|
|
275
|
+
+ " && printf '%s' '" + ignore_content + "' > '" + prebuild_dockerfile + ".dockerignore'"
|
|
276
|
+
+ " && docker build --network host --target production"
|
|
277
|
+
+ " -f '" + prebuild_dockerfile + "'"
|
|
278
|
+
+ " -t '" + _app_image_name(config['resource_name'], config['res_name']) + "'"
|
|
279
|
+
+ " '" + (project_root or '.') + "'"
|
|
280
|
+
)
|
|
281
|
+
local_resource(
|
|
282
|
+
name=config['res_name'] + '-image',
|
|
283
|
+
cmd=cmd,
|
|
284
|
+
labels=config['labels'],
|
|
285
|
+
resource_deps=config['res_deps'],
|
|
286
|
+
auto_init=auto_init_apps,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _resolve_dockerfile(config):
|
|
291
|
+
"""Absolute (when project_root is set) path of a resource's Dockerfile."""
|
|
248
292
|
project_root = config.get('project_root', '')
|
|
249
293
|
# Use custom dockerfile from config if specified, otherwise use autogenerated default
|
|
250
294
|
# The res_path is relative to project_root (e.g., 'services/product/...')
|
|
@@ -263,13 +307,7 @@ def _register_docker_build(config, live_update_rules):
|
|
|
263
307
|
dockerfile = project_root + dockerfile
|
|
264
308
|
else:
|
|
265
309
|
dockerfile = project_root + '/' + dockerfile
|
|
266
|
-
|
|
267
|
-
image_name,
|
|
268
|
-
project_root or '.',
|
|
269
|
-
dockerfile,
|
|
270
|
-
live_update_rules,
|
|
271
|
-
config['res_deps'],
|
|
272
|
-
)
|
|
310
|
+
return dockerfile
|
|
273
311
|
|
|
274
312
|
|
|
275
313
|
def _register_run_only_resource(config, resource_path, compose_project_name, auto_init_apps=True):
|
|
@@ -318,9 +356,11 @@ def _register_single_resource(config, resource_path, compose_project_name, auto_
|
|
|
318
356
|
|
|
319
357
|
# A sablier.enable + sablier.deferStart resource is held back from tdk up's
|
|
320
358
|
# normal bring-up: its container is never created or started here, only via
|
|
321
|
-
# the Traefik wake path on first request.
|
|
322
|
-
#
|
|
323
|
-
|
|
359
|
+
# the Traefik wake path on first request. auto_init=False also skips the
|
|
360
|
+
# dc_resource's docker_build, so its image is built by a separate
|
|
361
|
+
# `<name>-image` resource instead (_register_deferred_image_prebuild).
|
|
362
|
+
defers_start = resource_defers_start(config.get('manifest', {}))
|
|
363
|
+
effective_auto_init = auto_init_apps and not defers_start
|
|
324
364
|
|
|
325
365
|
print("DEBUG REGISTER: Registering '{}' app_type='{}' auto_init={}".format(res_name, app_type, effective_auto_init))
|
|
326
366
|
|
|
@@ -333,6 +373,8 @@ def _register_single_resource(config, resource_path, compose_project_name, auto_
|
|
|
333
373
|
config['syncs']
|
|
334
374
|
)
|
|
335
375
|
_register_docker_build(config, live_update_rules)
|
|
376
|
+
if defers_start:
|
|
377
|
+
_register_deferred_image_prebuild(config, auto_init_apps)
|
|
336
378
|
else:
|
|
337
379
|
print("DEBUG REGISTER: '{}' skipping docker_build (app_type='{}', syncs={})".format(res_name, app_type, config.get('syncs')))
|
|
338
380
|
|
|
@@ -162,9 +162,29 @@ def _build_typescript_service(name, context, dockerfile, live_update_rules, deps
|
|
|
162
162
|
)
|
|
163
163
|
|
|
164
164
|
|
|
165
|
+
def prebuild_dockerignore(dockerfile, project_root, res_path):
|
|
166
|
+
"""Allowlist .dockerignore matching _build_typescript_service's only=/ignore=.
|
|
167
|
+
|
|
168
|
+
A plain `docker build` has no only= filter, so without this it would send
|
|
169
|
+
the whole project root as context. `res_path` is relative to the project
|
|
170
|
+
root (the build context); `dockerfile` may be absolute.
|
|
171
|
+
"""
|
|
172
|
+
abs_res = project_root + '/' + res_path if project_root else res_path
|
|
173
|
+
lines = ['*']
|
|
174
|
+
for path in _get_resource_only_paths(abs_res):
|
|
175
|
+
lines.append('!' + (res_path if path == abs_res else path))
|
|
176
|
+
ignores = _load_autogenerated_dockerignore_patterns(dockerfile, res_path)
|
|
177
|
+
for pattern in get_filewatch_ignore_patterns(res_path):
|
|
178
|
+
if pattern not in ignores:
|
|
179
|
+
ignores.append(pattern)
|
|
180
|
+
lines.extend(ignores)
|
|
181
|
+
return '\n'.join(lines) + '\n'
|
|
182
|
+
|
|
183
|
+
|
|
165
184
|
TypescriptBuilders = struct(
|
|
166
185
|
build_typescript_service = _build_typescript_service,
|
|
167
186
|
load_dockerignore_patterns = _load_autogenerated_dockerignore_patterns,
|
|
187
|
+
prebuild_dockerignore = prebuild_dockerignore,
|
|
168
188
|
)
|
|
169
189
|
|
|
170
190
|
DEBUG = {}
|
package/install.sh
CHANGED
|
@@ -1,242 +1,19 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# TDK CLI
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# Print functions
|
|
21
|
-
print_info() {
|
|
22
|
-
echo -e "${BLUE}ℹ️ $1${NC}"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
print_success() {
|
|
26
|
-
echo -e "${GREEN}✅ $1${NC}"
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
print_warning() {
|
|
30
|
-
echo -e "${YELLOW}⚠️ $1${NC}"
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
print_error() {
|
|
34
|
-
echo -e "${RED}❌ $1${NC}"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
# Check if command exists
|
|
38
|
-
command_exists() {
|
|
39
|
-
command -v "$1" >/dev/null 2>&1
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
# Detect OS
|
|
43
|
-
detect_os() {
|
|
44
|
-
case "$(uname -s)" in
|
|
45
|
-
Linux*) echo "linux";;
|
|
46
|
-
Darwin*) echo "macos";;
|
|
47
|
-
CYGWIN*) echo "windows";;
|
|
48
|
-
MINGW*) echo "windows";;
|
|
49
|
-
MSYS*) echo "windows";;
|
|
50
|
-
*) echo "unknown";;
|
|
51
|
-
esac
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
# Check prerequisites
|
|
55
|
-
check_prerequisites() {
|
|
56
|
-
print_info "Checking prerequisites..."
|
|
57
|
-
|
|
58
|
-
OS=$(detect_os)
|
|
59
|
-
print_info "Detected OS: $OS"
|
|
60
|
-
|
|
61
|
-
# Check for git
|
|
62
|
-
if ! command_exists git; then
|
|
63
|
-
print_error "git is required but not installed."
|
|
64
|
-
echo "Please install git first:"
|
|
65
|
-
echo " macOS: brew install git"
|
|
66
|
-
echo " Linux: sudo apt-get install git (or your package manager)"
|
|
67
|
-
exit 1
|
|
68
|
-
fi
|
|
69
|
-
|
|
70
|
-
# Check for a JavaScript runtime (bun or node)
|
|
71
|
-
if command_exists bun; then
|
|
72
|
-
RUNTIME="bun"
|
|
73
|
-
print_success "Found bun runtime"
|
|
74
|
-
elif command_exists node; then
|
|
75
|
-
RUNTIME="node"
|
|
76
|
-
print_success "Found node runtime"
|
|
77
|
-
|
|
78
|
-
# Check for npm
|
|
79
|
-
if ! command_exists npm; then
|
|
80
|
-
print_error "npm is required with node but not found"
|
|
81
|
-
exit 1
|
|
82
|
-
fi
|
|
83
|
-
else
|
|
84
|
-
print_warning "No JavaScript runtime found (bun or node)"
|
|
85
|
-
echo ""
|
|
86
|
-
echo "Would you like to install Bun? (Recommended - much faster)"
|
|
87
|
-
echo " curl -fsSL https://bun.sh/install | bash"
|
|
88
|
-
echo ""
|
|
89
|
-
read -p "Install Bun now? [Y/n] " -n 1 -r
|
|
90
|
-
echo
|
|
91
|
-
if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then
|
|
92
|
-
print_info "Installing Bun..."
|
|
93
|
-
curl -fsSL https://bun.sh/install | bash
|
|
94
|
-
|
|
95
|
-
# Source bun setup
|
|
96
|
-
if [ -f "${HOME}/.bashrc" ]; then
|
|
97
|
-
export BUN_INSTALL="${HOME}/.bun"
|
|
98
|
-
export PATH="${BUN_INSTALL}/bin:$PATH"
|
|
99
|
-
fi
|
|
100
|
-
|
|
101
|
-
if command_exists bun; then
|
|
102
|
-
RUNTIME="bun"
|
|
103
|
-
print_success "Bun installed successfully"
|
|
104
|
-
else
|
|
105
|
-
print_error "Bun installation failed or not in PATH"
|
|
106
|
-
print_info "Please restart your terminal and run this script again"
|
|
107
|
-
exit 1
|
|
108
|
-
fi
|
|
109
|
-
else
|
|
110
|
-
print_error "Bun or Node.js is required to install TDK"
|
|
111
|
-
exit 1
|
|
112
|
-
fi
|
|
113
|
-
fi
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
# Setup directories
|
|
117
|
-
setup_directories() {
|
|
118
|
-
print_info "Setting up directories..."
|
|
119
|
-
|
|
120
|
-
mkdir -p "$INSTALL_DIR"
|
|
121
|
-
mkdir -p "$BIN_DIR"
|
|
122
|
-
|
|
123
|
-
print_success "Directories created"
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
# Clone or update repository
|
|
127
|
-
clone_repository() {
|
|
128
|
-
print_info "Cloning TDK CLI repository..."
|
|
129
|
-
|
|
130
|
-
if [ -d "${INSTALL_DIR}/tdk-cli" ]; then
|
|
131
|
-
print_warning "Existing installation found, updating..."
|
|
132
|
-
cd "${INSTALL_DIR}/tdk-cli"
|
|
133
|
-
git fetch origin
|
|
134
|
-
git reset --hard origin/main
|
|
135
|
-
else
|
|
136
|
-
git clone --depth 1 "$REPO_URL" "${INSTALL_DIR}/tdk-cli"
|
|
137
|
-
cd "${INSTALL_DIR}/tdk-cli"
|
|
138
|
-
fi
|
|
139
|
-
|
|
140
|
-
print_success "Repository cloned/updated"
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
# Install dependencies and link
|
|
144
|
-
install_and_link() {
|
|
145
|
-
print_info "Installing dependencies..."
|
|
146
|
-
|
|
147
|
-
cd "${INSTALL_DIR}/tdk-cli/cli"
|
|
148
|
-
|
|
149
|
-
if [ "$RUNTIME" = "bun" ]; then
|
|
150
|
-
bun install
|
|
151
|
-
print_success "Dependencies installed with bun"
|
|
152
|
-
|
|
153
|
-
print_info "Linking TDK CLI..."
|
|
154
|
-
bun link --force
|
|
155
|
-
print_success "TDK CLI linked globally"
|
|
156
|
-
else
|
|
157
|
-
npm install
|
|
158
|
-
print_success "Dependencies installed with npm"
|
|
159
|
-
|
|
160
|
-
print_info "Linking TDK CLI..."
|
|
161
|
-
npm link --force
|
|
162
|
-
print_success "TDK CLI linked globally"
|
|
163
|
-
fi
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
# Setup PATH
|
|
167
|
-
setup_path() {
|
|
168
|
-
print_info "Setting up PATH..."
|
|
169
|
-
|
|
170
|
-
SHELL_CONFIG=""
|
|
171
|
-
if [ -f "${HOME}/.zshrc" ]; then
|
|
172
|
-
SHELL_CONFIG="${HOME}/.zshrc"
|
|
173
|
-
elif [ -f "${HOME}/.bashrc" ]; then
|
|
174
|
-
SHELL_CONFIG="${HOME}/.bashrc"
|
|
175
|
-
elif [ -f "${HOME}/.bash_profile" ]; then
|
|
176
|
-
SHELL_CONFIG="${HOME}/.bash_profile"
|
|
177
|
-
fi
|
|
178
|
-
|
|
179
|
-
if [ -n "$SHELL_CONFIG" ]; then
|
|
180
|
-
if ! grep -q "\.bun/bin" "$SHELL_CONFIG" 2>/dev/null; then
|
|
181
|
-
echo "" >> "$SHELL_CONFIG"
|
|
182
|
-
echo "# TDK CLI (installed via install.sh)" >> "$SHELL_CONFIG"
|
|
183
|
-
echo 'export PATH="${HOME}/.bun/bin:${PATH}"' >> "$SHELL_CONFIG"
|
|
184
|
-
print_success "Added ~/.bun/bin to PATH in $(basename "$SHELL_CONFIG")"
|
|
185
|
-
print_warning "Please restart your terminal or run: source $SHELL_CONFIG"
|
|
186
|
-
else
|
|
187
|
-
print_info "PATH already configured in $(basename "$SHELL_CONFIG")"
|
|
188
|
-
fi
|
|
189
|
-
else
|
|
190
|
-
print_warning "Could not detect shell config file"
|
|
191
|
-
print_info "Please manually add to your shell config:"
|
|
192
|
-
echo 'export PATH="${HOME}/.bun/bin:${PATH}"'
|
|
193
|
-
fi
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
# Verify installation
|
|
197
|
-
verify_installation() {
|
|
198
|
-
print_info "Verifying installation..."
|
|
199
|
-
|
|
200
|
-
export PATH="${BIN_DIR}:${PATH}"
|
|
201
|
-
|
|
202
|
-
if command_exists tdk; then
|
|
203
|
-
VERSION=$(tdk -v 2>/dev/null || echo "unknown")
|
|
204
|
-
print_success "TDK CLI installed successfully!"
|
|
205
|
-
echo ""
|
|
206
|
-
echo "Version: $VERSION"
|
|
207
|
-
echo "Location: $(which tdk)"
|
|
208
|
-
echo ""
|
|
209
|
-
echo "Quick start:"
|
|
210
|
-
echo " tdk --help # Show all commands"
|
|
211
|
-
echo " tdk project # Initialize a new project"
|
|
212
|
-
echo " tdk resource api # Create a new resource"
|
|
213
|
-
echo ""
|
|
214
|
-
print_info "Happy coding! 🚀"
|
|
215
|
-
else
|
|
216
|
-
print_error "Installation verification failed"
|
|
217
|
-
print_info "tdk command not found in PATH"
|
|
218
|
-
print_info "You may need to restart your terminal or run:"
|
|
219
|
-
echo " export PATH=\"${HOME}/.bun/bin:\${PATH}\""
|
|
220
|
-
exit 1
|
|
221
|
-
fi
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
# Main installation flow
|
|
225
|
-
main() {
|
|
226
|
-
echo ""
|
|
227
|
-
echo "╔════════════════════════════════════════════════════════════╗"
|
|
228
|
-
echo "║ 🚀 TDK CLI Installer ║"
|
|
229
|
-
echo "║ Tilt Development Kit - Install Script ║"
|
|
230
|
-
echo "╚════════════════════════════════════════════════════════════╝"
|
|
231
|
-
echo ""
|
|
232
|
-
|
|
233
|
-
check_prerequisites
|
|
234
|
-
setup_directories
|
|
235
|
-
clone_repository
|
|
236
|
-
install_and_link
|
|
237
|
-
setup_path
|
|
238
|
-
verify_installation
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
# Run main function
|
|
242
|
-
main "$@"
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Legacy installer URL for the TDK CLI.
|
|
3
|
+
#
|
|
4
|
+
# The official installer is https://tdk-landscape.github.io/install.sh. It
|
|
5
|
+
# installs the prebuilt `tdk` binary plus its bundled engine, verified
|
|
6
|
+
# against the release checksums, with no Node or Bun required. This script
|
|
7
|
+
# used to clone this repo and `bun link` it instead; it now hands off to the
|
|
8
|
+
# official installer so old
|
|
9
|
+
# curl -fsSL https://raw.githubusercontent.com/tdk-landscape/tdk-cli-core/main/install.sh | bash
|
|
10
|
+
# commands keep working and every install method gets the same result.
|
|
11
|
+
#
|
|
12
|
+
# To work on TDK itself, clone the repo instead (see CONTRIBUTING.md).
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
readonly OFFICIAL_INSTALLER="https://tdk-landscape.github.io/install.sh"
|
|
17
|
+
|
|
18
|
+
echo "Using the official TDK installer: ${OFFICIAL_INSTALLER}" >&2
|
|
19
|
+
curl -fsSL "${OFFICIAL_INSTALLER}" | sh
|
|
@@ -35,6 +35,8 @@ See `proposal.md` (Why) for the motivating case. Relevant current behavior:
|
|
|
35
35
|
|
|
36
36
|
Add a `deferStart` key to the manifest's existing `sablier` block (`engine/topologies/tilt/manifest/schema.star`'s `sablier` schema, alongside `enable`/`group`/`sessionDuration`), default `false`. `_register_replicas` (and any other call site that currently receives the single `auto_init_apps` flag for app resources) resolves per-resource auto-init as `auto_init_apps and not resource_defers_start(manifest)` instead of using `auto_init_apps` directly. The resource's **config-gen** and **docker_build** resources keep `auto_init=True` unconditionally (or follow `auto_init_config_gen`, already `True` by default) so the image still builds during `tdk up` — only the running container is held back.
|
|
37
37
|
|
|
38
|
+
**Corrected live (2026-09-27, task 7.2/7.7):** that last sentence assumed wrongly. In this codebase `docker_build` has no `auto_init` of its own: Tilt attaches the image target to the `dc_resource` that deploys it, so `auto_init=False` skips the image build too. A `tdk up` on `tdk-erp-system` recorded zero builds for the deferred `data-governance-api`. **Fix:** each `deferStart` resource also gets a `<name>-image` `local_resource` (auto-init follows the landscape-wide `auto_init_apps`, not the deferred flag) that runs `docker build --target production --network host` into the tag the compose service declares. A plain `docker build` has no `only=` filter, so it builds from a copy of the Dockerfile (`<Dockerfile>.prebuild`) whose Dockerfile-specific `.dockerignore` is an allowlist generated from the same `only=`/`ignore=` lists `docker_build` uses (`TypescriptBuilders.prebuild_dockerignore`). Verified on `data-governance-api`: 14 kB build context, every layer served from the cache Tilt's own build populated, and filesystem layers identical to Tilt's image (only Tilt's `dev.tilt.*` labels differ). Tilt's own `docker_build` stays registered, so the first `tilt trigger` still gets live update.
|
|
39
|
+
|
|
38
40
|
*Alternatives considered:*
|
|
39
41
|
- A separate global "cold landscape" mode (e.g. `TILT_DEFER_ALL_APPS`): rejected because it can't express "just this one resource," which is the actual request (one API, not the whole landscape).
|
|
40
42
|
- Piggybacking on `TILT_TRIGGER_MODE=manual` wholesale: rejected — that already exists and disables `enforce_migrator_deps` and replica counts landscape-wide; overloading it would change unrelated behavior for every resource, not just opted-in ones.
|
|
@@ -67,7 +69,9 @@ Either way, the gateway is the single thing the static route (D4) points at, and
|
|
|
67
69
|
- Confirmed live: the Tilt/Compose *resource* name (what `tilt trigger` and Compose's own `depends_on` use) is not the same string as the Docker *container* name Compose actually creates (`<project>-<service>-1`, e.g. `analytics-autogenerated-data-governance-api-1` for resource `data-governance-api`) — `docker inspect` needs the latter. The gateway and the generated route both carry both identifiers (`X-Wake-Resource` / `X-Wake-Container`) rather than assuming they're interchangeable.
|
|
68
70
|
- A full disposable rehearsal (isolated Tilt + Docker Compose + the built gateway image, torn down after) woke a cold `traefik/whoami` container from both "exited" and fully "absent" states and correctly proxied a request through with its original path intact.
|
|
69
71
|
|
|
70
|
-
**
|
|
72
|
+
**Verified live against `tdk-erp-system` (2026-09-27):** with the landscape quiet, the original URL answered `200` from a fully cold container in 19.2s via the direct compose start (task 7.2).
|
|
73
|
+
|
|
74
|
+
**Early `503` + `Retry-After` (task 7.8):** during a full `tdk up` bring-up the Docker daemon itself was the bottleneck: the direct start took ~5 min, and Bun's 255s idle cap dropped the held request with no response at all. Holding the request longer can't fix a saturated daemon, so the gateway now holds a waking request for at most 60s (`EARLY_RESPONSE_MS`, overridable via `X-Wake-Respond-Within-Ms`, capped at 240s), then answers `503` with `Retry-After: 10` while the start continues in the background. One wake runs per resource at a time: a retry, or another caller arriving meanwhile, joins the wake in progress rather than starting the container again. A resource that becomes healthy within the window is still answered directly, so the quiet-landscape case is unchanged.
|
|
71
75
|
|
|
72
76
|
### D4: A never-created resource's route comes from Traefik's static/file provider, not Docker-label discovery
|
|
73
77
|
|
|
@@ -13,7 +13,7 @@ A resource with a `sablier` manifest block SHALL be able to mark itself deferred
|
|
|
13
13
|
#### Scenario: Deferred resource is not started during tdk up
|
|
14
14
|
|
|
15
15
|
- **WHEN** `tdk up` runs a landscape containing a resource with deferred start enabled
|
|
16
|
-
- **THEN** that resource's image build completes during the run
|
|
16
|
+
- **THEN** that resource's image build completes during the run, under the image tag its compose service declares, so its first request can start it without building
|
|
17
17
|
- **AND** the resource's container is not started, and `tdk up` does not wait on it to become healthy before finishing bring-up of the rest of the landscape
|
|
18
18
|
|
|
19
19
|
#### Scenario: Non-opted-in resource is unaffected
|
|
@@ -65,13 +65,19 @@ Waking a deferred resource SHALL also wake any of its required startup dependenc
|
|
|
65
65
|
|
|
66
66
|
### Requirement: A Waking Request Waits For Health, Not Just Start
|
|
67
67
|
|
|
68
|
-
A request that triggers a deferred resource's startup SHALL be held until the resource passes its health check or until a bounded timeout elapses, rather than being answered as soon as the container process starts.
|
|
68
|
+
A request that triggers a deferred resource's startup SHALL be held until the resource passes its health check, until a bounded hold window elapses, or until a bounded timeout elapses, rather than being answered as soon as the container process starts. The caller SHALL always receive a response; the connection SHALL NOT be dropped silently.
|
|
69
69
|
|
|
70
70
|
#### Scenario: Client receives the real response
|
|
71
71
|
|
|
72
|
-
- **WHEN** a request wakes a deferred resource
|
|
72
|
+
- **WHEN** a request wakes a deferred resource that becomes healthy within the hold window
|
|
73
73
|
- **THEN** the client's request is held and then answered by the resource once it is healthy, rather than receiving an immediate "starting" response with no real answer
|
|
74
74
|
|
|
75
|
+
#### Scenario: Startup outlasts the hold window
|
|
76
|
+
|
|
77
|
+
- **WHEN** a request wakes a deferred resource that is still not healthy when the hold window ends (e.g. the Docker daemon is saturated by a full `tdk up` bring-up)
|
|
78
|
+
- **THEN** the request is answered with `503` and a `Retry-After` header while the start continues in the background
|
|
79
|
+
- **AND** a retry, or any other request that arrives meanwhile, joins that same start instead of starting the resource again, and is answered by the resource once it is healthy
|
|
80
|
+
|
|
75
81
|
#### Scenario: Startup exceeds the timeout
|
|
76
82
|
|
|
77
83
|
- **WHEN** a deferred resource does not become healthy within its configured wake timeout
|
|
@@ -46,6 +46,15 @@
|
|
|
46
46
|
- Added the `sablier` block to `data-governance-api/service.json`, re-vendored, and confirmed the generated route (`traefik-dynamic/data-governance-api.yml`) and cold behavior (no container until first request) all work as designed.
|
|
47
47
|
- First real pass found and fixed two genuine bugs (not environment noise): (a) task 7.4's queue-bypass fix (`tilt trigger` alone queued behind Tilt's build-slot cap and 504'd — see D3); (b) after that fix, a second real bug — the app only serves its bare health path (`/health`), and the generated wake route forwarded the full public path (`/api/data-governance/health`) unstripped, unlike the real Docker-label `-project` router, so a successful wake still 404'd. Fixed by adding a matching `stripPrefix` middleware to the generated route (`traefik_static_routes.star`), reusing the same `cli_api_path()` the Docker-label router strips with. Both fixes are unit/Starlark-tested (33/33 passing) and re-vendored into the live project.
|
|
48
48
|
- **Re-test after both fixes is inconclusive, not failing**: a `docker rm -f` + cold curl got a `502` from Traefik itself (not the gateway's own 504), and the gateway's log showed only its initial "wake" decision line, never a "compose start ... started/failed" result — `docker compose up` inside the gateway appears to have stalled rather than erred. Root-caused to the machine, not the code: `tilt get uiresource` showed **104 of 250 resources still `pending`**, mid a mass rebuild (Tilt's build-slot cap processing 3 at a time) triggered by this task's own repeated `tdk project --yes` + forced-Tiltfile-re-eval cycles across this session — sustained load average ~26-27, `docker ps`/`traefik ping` themselves taking 10-30s, and Traefik logged a stale `data-governance-api@docker` service IP getting "no route to host" consistent with a container that started to come up and was torn down mid-flight under this contention. **Decision (2026-09-27, developer's own call, not further probed by any session)**: stop touching the live landscape rather than keep polling an already-overloaded daemon (load average climbed to ~38 after this note was first written, queue hadn't drained) or force a Docker Desktop restart that would kill the ~110 containers of a 14+-hour-running landscape. The code changes (task 7.4's queue-bypass fix and this task's strip-prefix fix) ship as-is on the strength of their unit/Starlark tests (33/33 passing) plus the one clean live pass that *did* complete end-to-end before the path-stripping bug was found (container created from cold via direct compose start, no Tilt-queue wait, "compose start data-governance-api: started" logged, and a genuine 502→200 progression as each bug was fixed in turn) — not on an unattainable final green run under a saturated host. This task stays open (checkbox unchecked) rather than being marked done on inference: the one remaining step is a single clean re-run of `curl http://api.tdk-erp-system.localhost/api/data-governance/health` against a quiescent `tdk-erp-system` landscape, entirely at the developer's own convenience, with no further re-vendor/re-eval cycles needed first (the fixes are already vendored in).
|
|
49
|
+
- **Live re-test passed, 2026-09-27 18:55** (landscape quiet: Tilt no longer running, load ~17, no re-vendor/re-eval needed): warm `curl http://api.tdk-erp-system.localhost/api/data-governance/health` → `200` with the real health body in 0.6s (the same request 404'd before task 7.5's strip-prefix fix). Then `docker rm -f` the container, confirmed absent, same `curl` → **`200` `{"status":"healthy",...}` in 19.2s** from fully cold. Gateway log: `wake data-governance-api: state=absent compose=true trigger=[]` → `compose start data-governance-api: started` — task 7.4's direct-start path, no Tilt involvement at all (Tilt was not even running). This closes the proposal's motivating gap on the real landscape. Side observation: Traefik's own Docker-label routers for this resource are `disabled` because the Sablier Traefik plugin fails its integrity check on download (`plugin integrity check failed`, plugins disabled), so every request currently goes through the wake route — a separate, pre-existing plugin-download problem, not part of this change.
|
|
50
|
+
- **Still unverified live (why the box stays unchecked):** the two parts of 7.2 that need Tilt itself running — (a) task 3.3, that a fresh `tdk up` leaves `data-governance-api` with no container until its first request, and (b) that `tdk doctor` reports it as deferred rather than stalled. Both are covered by unit tests (3.1/3.2 predicate tests, 6.2's doctor tests) but not yet observed on this landscape. Next step: one `tdk up` in `tdk-erp-system`, then `docker ps -a --filter name=data-governance-api` (expect nothing) and `tdk doctor`.
|
|
51
|
+
- **`tdk up` run, 2026-09-27 19:08 (global `tdk` 1.3.51, premium overlay in place, container removed first):**
|
|
52
|
+
- ✅ `tdk up`'s summary printed `data-governance-api: .../api/data-governance/health (deferred — starts on first request)` (task 6.1, live).
|
|
53
|
+
- ✅ After the Tiltfile evaluated, Tilt left `data-governance-api` at `updateStatus: none` / `runtimeStatus: none` and created no container (task 3.3's container half, live).
|
|
54
|
+
- ❌ **Image not built.** Contrary to the design comment in `_register_single_resource` and the spec's "Deferred Start Opt-In" requirement, `auto_init=False` skips the resource's image build as well as its container: this Tilt session recorded zero builds for `data-governance-api`, and its newest image predates the session. The image only existed because earlier sessions built it. On a fresh project the first wake finds no image, `ensureImage()` fails, and the gateway falls back to `tilt trigger` — the queueing path task 7.4 was meant to avoid.
|
|
55
|
+
- ❌ **Cold wake during a full bring-up timed out for the caller.** Hit the URL at 19:10:42 with 134 resources pending: the gateway chose the direct compose path (`state=absent compose=true`), but `docker image inspect` took ~2 min and `docker compose up` ~3 min more because the Docker daemon itself was saturated by the bring-up (`tdk doctor` also aborted: `docker ps` hung >10s). The container started at 19:15:36 (~5 min), after Bun's 255s idle timeout had already dropped the client connection (`HTTP 000`). A follow-up request returned `200` in 16s. So bypassing Tilt's build queue works, but under a full bring-up the Docker daemon is the next bottleneck, and the gateway gives the caller no response in that case.
|
|
56
|
+
- ⏸ `tdk doctor`'s deferred reporting (6.2) not observed yet: doctor exits at its Docker-responsiveness check while the daemon is this loaded.
|
|
57
|
+
- **Open decisions, resolved by the developer 2026-09-27:** (1) build the image during `tdk up` → task 7.7; (2) answer slow wakes with an early `503` + `Retry-After` → task 7.8. Both implemented and tested; neither re-vendored into `tdk-erp-system` yet. **What remains for this task:** re-vendor, then one `tdk up` to confirm the `data-governance-api-image` resource builds and the container stays absent, a cold request during bring-up to confirm a `503` + `Retry-After` followed by a successful retry, and `tdk doctor` once the Docker daemon is responsive enough for its 10s check.
|
|
49
58
|
- **2026-09-27 disposable probe (torn down after, nothing kept):** to verify task 7.3's fix end-to-end rather than only at the Starlark-unit level, stood up an isolated Tilt + Docker Compose project (two `traefik/whoami` services, `dep-service` and `primary-service`, both `dc_resource(auto_init=False)`) plus a standalone Traefik with the file provider enabled. Generated `primary-service`'s static route with the **real, unmodified** `generate_static_wake_route()` from `traefik_static_routes.star`, passing `dependencies=[("dep-service", "wakeprobe")]` the same shape `resolve_defer_start_dependencies` now produces — confirmed the emitted YAML carries `X-Wake-Deps: "dep-service=wakeprobe-dep-service-1"`. Ran the real `wake-gateway/server.ts` (as a local Bun process against this container's own Tilt daemon and Docker socket, since building the packaged Docker image failed here on an unrelated Alpine/`apk` proxy TLS issue — the packaged image itself is unaffected, this only affected building it ad hoc in this sandbox). A single HTTP request against `primary-service`'s route, while both containers were confirmed absent beforehand, resulted in **both** `wakeprobe-primary-service-1` and `wakeprobe-dep-service-1` being created and started (verified via `docker ps` and `tilt logs` showing both `tilt trigger` calls succeed) — this is the exact behavior task 7.3 added and that D5's requirement describes, now observed working end-to-end, not just unit-tested. The final proxy-through step returned a connection error, but only because the gateway ran as a host process outside the Compose network and so couldn't resolve the container's Compose-DNS name (`primary-service`) — confirmed by curling the container's bridge IP directly and getting a real `200`; that proxy-through mechanic itself was already verified live in task 4.3's own probe when the gateway ran inside the correct Docker network, and is unrelated to 7.3's change. One real, unrelated hiccup along the way: `primary-service`'s first `tilt trigger` failed with a Docker Hub `429 Too Many Requests` on the image pull (transient registry throttling, not a bug); a second trigger with the image already cached succeeded normally.
|
|
50
59
|
- [x] 7.3 (Found 2026-09-26 re-reading the shipped code) Wire real dependency data into the `generate_static_wake_route(...)` call at `apply_compose_resource_registration.star:442` — it always passed no `dependencies=` argument, so every generated route shipped `X-Wake-Deps: ""` despite the gateway side and the generator's `dependencies` param both being implemented and unit-tested in isolation. **Done, 2026-09-26**: added `resolve_manifest_dependency_names(manifest, all_services_map)` (reuses the existing `_resolve_dependency_to_resource` that `_build_resource_deps` already trusts for Tilt's own `resource_deps` ordering — an ambiguous name behaves identically here as it already does there) and `resolve_defer_start_dependencies(manifest, resource_manifests, all_services_map)` (filters those resolved names to the ones whose own manifest is itself `resource_defers_start`), both in `apply_compose_resource_registration.star`, no leading underscore so they're directly `load()`-able for tests per task 3.1's precedent. The call site now passes `dependencies=resolve_defer_start_dependencies(manifest, resource_manifests, all_services_map)`. 6 new cases in `test_sablier_defer_start.py` cover: exact-name resolution, an unresolvable name falling back to exclusion (not a guess), a dependency that resolves but isn't itself deferStart, and the free-tier license gate keeping the result empty even for a `dependsOn` target whose manifest asks for `deferStart` (mirrors task 3.1's own license-gate tests, since `resource_defers_start` is reused unchanged) — full 166/166 passing (166 = prior 160 + these 6; the pre-existing 29 unrelated failures in `tests/tilt-engine/` — `test_agents_md_*`, `test_daemon_*`, `test_snapshot_scanning`, etc. — are identical before and after this change, confirmed by diffing the failure list against a `git stash` baseline). The "licensed and actually wakes a peer deferStart resource" end-to-end case still can't be exercised from this repo's free-tier stub, same limitation task 3.1 already documented — folded into task 7.2's live run rather than duplicated here.
|
|
51
60
|
|
|
@@ -53,4 +62,8 @@
|
|
|
53
62
|
|
|
54
63
|
- [x] 7.6 Benchmark task 7.4's queue-bypass fix with real, reproducible numbers rather than relying solely on the one interrupted live pass. **Done, 2026-09-27**: a disposable, isolated benchmark (own Tilt instance on a private port, own Compose project, torn down completely after — no interaction with any real project) exercising the actual shipped `generate_static_wake_route()`/`decide.ts`/`server.ts` code against a genuine build-slot queue (`max_parallel_updates=2`, six slow-building filler resources). Full setup, results table, and interpretation recorded in `design.md`'s new "Benchmark: D3's queue-bypass fix, measured" section. Headline results: the new direct-start path (`target-fast`) answered in 7.4-12.6s regardless of whether the build queue was saturated; the old `tilt trigger`-only fallback (`target-slow`) cost 18.1-22.8s even at its best (idle) case, confirmed via Tilt's own build history to be paying its build-reconciliation step unconditionally — the same step that queues behind other builds and caused the original live `504`.
|
|
55
64
|
|
|
65
|
+
- [x] 7.7 (Found live, task 7.2's `tdk up` run, 2026-09-27) Build a deferred resource's image during `tdk up`: `auto_init=False` also skipped its `docker_build`, contrary to D1's original assumption. **Done** (`3f25fe6`): `_register_deferred_image_prebuild` adds a `<name>-image` `local_resource` per `deferStart` resource that builds the same image under the compose-declared tag, using a Dockerfile copy with an allowlist `.dockerignore` from the new `TypescriptBuilders.prebuild_dockerignore` (mirrors `docker_build`'s `only=`/`ignore=`). New `test_prebuild_dockerignore_mirrors_docker_build_only_and_ignore` case; 35/35 related Starlark tests pass. Verified by hand on `data-governance-api` with the exact command the resource runs (throwaway tag): 14 kB context, all layers cached, filesystem layers identical to Tilt's image.
|
|
66
|
+
|
|
67
|
+
- [x] 7.8 (Found live, task 7.2's `tdk up` run, 2026-09-27) Never drop a waking request silently. **Done** (`3f25fe6`): `server.ts` holds for `earlyResponseMs()` (60s default, `X-Wake-Respond-Within-Ms` override capped at 240s under Bun's 255s idle limit), then answers `503` + `Retry-After: 10` while the start continues; an in-flight map keeps one wake per resource so retries join it. Spec updated ("Startup outlasts the hold window" scenario). 18/18 `bun test` cases pass (4 new for the timing rules); `server.ts`/`decide.ts` type-check under `strict` with Bun types. Not yet exercised live: the in-flight join and the 503 path need a slow start to observe (task 7.2's remaining step).
|
|
68
|
+
|
|
56
69
|
- [x] 7.4 (Found live during task 7.2's real `tdk-erp-system` run, 2026-09-27) `tilt trigger`-only wake failed under real load: with ~100+ resources mid-rebuild after a re-vendor (Tilt caps concurrent builds at a handful of slots), a triggered `deferStart` resource sat queued behind them and the request timed out with a `504` — the exact "wait behind a huge landscape" problem this feature exists to remove, just relocated to Tilt's build queue. **Done**: the gateway now prefers creating/starting the resource directly with `docker compose up -d --no-build <resource>` (the same command Tilt's own `<resource>-run-only` local_resource runs) whenever the generated route supplies the resource's compose invocation, falling back to `tilt trigger` only when no image has ever been built for it yet (`ensureImage()` first tries retagging Tilt's own `<repo>:tilt-<hash>` build as `<repo>:dev` in case the plain tag was never created). Changes: `decide.ts`'s `decideWakeAction` gained `useComposeStart`/`hasComposeInvocation` and `wakeTimeoutMs()` (180s for a direct start, 240s when a build might be needed, under Bun's 255s idle cap) with new `decide.test.ts` cases; `server.ts` gained `composeStart()`/`ensureImage()` and reads `X-Wake-Compose-Project`/`X-Wake-Compose-Files`/`X-Wake-Env-File`/`X-Wake-Image`; `traefik_static_routes.star`'s `generate_static_wake_route` gained matching optional params/headers (new `test_static_route_carries_compose_invocation_for_direct_start` case) plus a `normalize_abs_path()` helper (Tilt's `os.path.abspath` doesn't collapse `..`, and the generated Tiltfile's project root is exactly `config.main_dir + "/../.."` — confirmed with a throwaway probe, new `test_normalize_abs_path_collapses_dot_segments` case); `apply_compose_resource_registration.star` gained `_wake_compose_invocation()` wiring the resource's actual compose files/env/image into the call site; `traefik_standalone.star` mounts the project root read-only into the gateway container at the same normalized absolute path so those compose files resolve identically there (new `test_wake_gateway_mounts_project_root_at_its_own_absolute_path` case). Dockerfile gained `docker-cli-compose`. 33/33 Starlark tests and the full `bun test` suite (25 assertions) pass. Live re-verification against `tdk-erp-system` (re-vendored, route regenerated with the new headers, gateway/Traefik rebuild in progress under the same real build-queue contention that motivated this) folded into 7.2's final result below rather than duplicated here.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tdk-landscape/tdk-cli-core",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.53",
|
|
4
4
|
"description": "Run 100 microservices on a 16 GB laptop without Kubernetes. Scaffold services and run them locally with hot reload, built on Tilt.",
|
|
5
5
|
"homepage": "https://tdk-landscape.github.io/tdk-website",
|
|
6
6
|
"repository": {
|
|
@@ -45,14 +45,17 @@ cp -R "${ROOT_DIR}/cli/templates" "${RELEASE_DIR}/tdk-cli/cli/templates"
|
|
|
45
45
|
|
|
46
46
|
(
|
|
47
47
|
cd "${RELEASE_DIR}"
|
|
48
|
-
shasum -a 256 tdk-linux-amd64 tdk-linux-arm64 tdk-darwin-amd64 tdk-darwin-arm64 > checksums.txt
|
|
49
|
-
zip -qr "tdk-cli-${RELEASE_TAG}-binaries.zip" \
|
|
50
|
-
tdk-linux-amd64 tdk-linux-arm64 tdk-darwin-amd64 tdk-darwin-arm64 \
|
|
51
|
-
tdk-cli checksums.txt
|
|
52
48
|
# Fixed filename (no version/tag in the name) so install.sh can always
|
|
53
49
|
# find it via the stable /releases/latest/download/ URL, unlike the zip
|
|
54
|
-
#
|
|
50
|
+
# below whose name embeds the tag and changes every release.
|
|
55
51
|
tar -czf tdk-cli-engine.tar.gz tdk-cli
|
|
52
|
+
# install.sh and `tdk upgrade` verify the binary and the engine tarball
|
|
53
|
+
# against this file before installing them.
|
|
54
|
+
shasum -a 256 tdk-linux-amd64 tdk-linux-arm64 tdk-darwin-amd64 tdk-darwin-arm64 \
|
|
55
|
+
tdk-cli-engine.tar.gz > checksums.txt
|
|
56
|
+
zip -qr "tdk-cli-${RELEASE_TAG}-binaries.zip" \
|
|
57
|
+
tdk-linux-amd64 tdk-linux-arm64 tdk-darwin-amd64 tdk-darwin-arm64 \
|
|
58
|
+
tdk-cli checksums.txt
|
|
56
59
|
)
|
|
57
60
|
|
|
58
61
|
echo "Built release assets in ${RELEASE_DIR}"
|
|
@@ -86,7 +86,7 @@ DB_WAIT_INTERVAL="${DB_WAIT_INTERVAL:-2}"
|
|
|
86
86
|
# =============================================================================
|
|
87
87
|
#
|
|
88
88
|
# Problem: Tilt creates databases but doesn't know what Infisical contains.
|
|
89
|
-
# This causes DATABASE_URL mismatch (e.g.,
|
|
89
|
+
# This causes DATABASE_URL mismatch (e.g., tdk_project_staff vs staff_db_prod)
|
|
90
90
|
#
|
|
91
91
|
# Solution: TILT_* prefixed variables ALWAYS override Infisical secrets
|
|
92
92
|
# Tilt sets TILT_DATABASE_URL → we export it as DATABASE_URL BEFORE infisical run
|
|
@@ -151,7 +151,7 @@ wait_for_postgres() {
|
|
|
151
151
|
|
|
152
152
|
# If we have psql, do a deeper health check
|
|
153
153
|
if command -v psql >/dev/null 2>&1; then
|
|
154
|
-
if PGPASSWORD="${db_password:-}" psql -h "${db_host}" -p "${db_port}" -U "${db_user:-
|
|
154
|
+
if PGPASSWORD="${db_password:-}" psql -h "${db_host}" -p "${db_port}" -U "${db_user:-tdk_project}" -d "${db_name}" -c "SELECT 1" >/dev/null 2>&1; then
|
|
155
155
|
log_success "✅ Database ${db_name} is ready!"
|
|
156
156
|
return 0
|
|
157
157
|
fi
|
|
@@ -191,6 +191,47 @@ def test_resolve_manifest_dependency_names_exact_match(tmp_path):
|
|
|
191
191
|
assert _run_resolve_names(tmp_path, manifest, all_services_map) == ["identity-management-backend"]
|
|
192
192
|
|
|
193
193
|
|
|
194
|
+
def test_prebuild_dockerignore_mirrors_docker_build_only_and_ignore(tmp_path):
|
|
195
|
+
"""A deferStart resource's image is pre-built by a plain `docker build`
|
|
196
|
+
(auto_init=False skips the dc_resource's own docker_build -- found live,
|
|
197
|
+
task 7.2). A plain build has no only= filter, so the generated allowlist
|
|
198
|
+
must include exactly what docker_build's only= does (root lockfiles, the
|
|
199
|
+
service, docker-templates, its internal libraries) and re-exclude its
|
|
200
|
+
ignore= patterns, or the whole project root becomes the build context."""
|
|
201
|
+
project = tmp_path / "project"
|
|
202
|
+
service = project / "services" / "analytics" / "data-governance-api"
|
|
203
|
+
(service / ".autogenerated").mkdir(parents=True)
|
|
204
|
+
(service / "package.json").write_text(
|
|
205
|
+
json.dumps({"dependencies": {"@tdk-project/platform-logging": "workspace:*", "zod": "^3"}})
|
|
206
|
+
)
|
|
207
|
+
dockerfile = service / ".autogenerated" / "Dockerfile.app.autogenerated"
|
|
208
|
+
dockerfile.write_text("FROM scratch\n")
|
|
209
|
+
(service / ".autogenerated" / "Dockerfile.app.autogenerated.dockerignore").write_text(
|
|
210
|
+
"# comment\nnode_modules\n*.md\n!.env.example\n"
|
|
211
|
+
)
|
|
212
|
+
tiltdir = tmp_path / "tilt"
|
|
213
|
+
tiltdir.mkdir()
|
|
214
|
+
r = run_starlark(
|
|
215
|
+
tiltdir,
|
|
216
|
+
"load('@ORCHESTRATOR/builders/typescript.star', 'prebuild_dockerignore')\n"
|
|
217
|
+
f"r = {{'content': prebuild_dockerignore({str(dockerfile)!r}, {str(project)!r}, "
|
|
218
|
+
"'services/analytics/data-governance-api')}\n",
|
|
219
|
+
)
|
|
220
|
+
lines = r["content"].splitlines()
|
|
221
|
+
res = "services/analytics/data-governance-api"
|
|
222
|
+
assert lines[0] == "*"
|
|
223
|
+
for allowed in ["package.json", "bun.lock", res, "shared-platform-engineering/docker-templates",
|
|
224
|
+
"shared-platform-engineering/platform-logging"]:
|
|
225
|
+
assert "!" + allowed in lines, (allowed, lines)
|
|
226
|
+
# Only the service's own relative path is allowed, never the absolute one.
|
|
227
|
+
assert not any(line.startswith("!" + str(project)) for line in lines), lines
|
|
228
|
+
# Re-excludes come after the allowlist (dockerignore: later lines win).
|
|
229
|
+
assert res + "/node_modules" in lines and res + "/*.md" in lines
|
|
230
|
+
assert lines.index(res + "/node_modules") > lines.index("!" + res)
|
|
231
|
+
# The Dockerfile's own negations aren't carried over (same as docker_build's ignore=).
|
|
232
|
+
assert not any(".env.example" in line for line in lines)
|
|
233
|
+
|
|
234
|
+
|
|
194
235
|
def test_resolve_manifest_dependency_names_dedupes_and_skips_empty(tmp_path):
|
|
195
236
|
manifest = {"dependsOn": []}
|
|
196
237
|
assert _run_resolve_names(tmp_path, manifest, {}) == []
|