
Volcengine Prepare
- 31 installs
- 16 repo stars
- Updated August 3, 2026
- volcengine/volcengine-skills
Helps with ai & agent building tasks.
About
volcengine-prepare is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- volcengine-prepare
- AI & Agent Building
- AI-coding skill
Volcengine Prepare by the numbers
- 31 all-time installs (skills.sh)
- +2 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #9,100 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/volcengine/volcengine-skills --skill volcengine-prepareAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 31 |
|---|---|
| repo stars | ★ 16 |
| Last updated | August 3, 2026 |
| Repository | volcengine/volcengine-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Volcengine Prepare Skill
Analyze a repo, explain viable Volcengine deployment paths, and decide the resource management path. Treat this skill as decision support, not as a workflow engine. Do not make a heavy report schema the goal.
---
0. Core behavior
Default flow:
1. Resolve the repo from a local path or Git URL. 2. Run the analyzer to identify language, framework, port, Docker/compose shape, dependencies, migrations, entrypoint, and the deployable service surface. 3. Optionally verify the current Volcengine identity and region when credentials are available. 4. Present a ranked list of ECS / VKE / veFaaS only after a deployable service surface is clear. Include every materially viable path; explain why each path is attractive or costly. Use ecs | vke | vefaas as machine-readable mode values. 5. Recommend a resource management path, but ask the user to choose cli or iac. Recommend IaC for VKE, managed dependencies, team-managed infrastructure, or plan/diff/destroy requirements; recommend CLI for pure ECS single-VM deployments, temporary validation, missing Terraform, blocked provider registry access, or explicit CLI preference. 6. Ask only for product/lifecycle ambiguity, resource reuse, and the resource management choice. If the user says "you decide", use the first ranked runtime path, the recommended resource management path from these rules, and new isolated resources. 7. Persist only minimal state in .volcengine/ when the work will continue across steps.
Before ranking ECS / VKE / veFaaS, identify the concrete deploy target: the repo, subdirectory, command, artifact, static output, or existing cloud app/function that a path can actually run, containerize, expose, or serve. File-level signals are evidence, not conclusions. A Dockerfile, compose file, package.json, framework dependency, or build/dev/test script does not by itself prove the repo is deployable.
Do not run strict tool dependency checks during recommendation. Check path-specific tools only after the user chooses a path.
State directory:
.volcengine/
deploy-choice.json # chosen mode/resource strategy, when persistence is useful
created-resources.json # maintained by deploy only for CLI fast path
terraform/ # IaC working files, only when infra_management=iac
iac-outputs.json # Terraform outputs consumed by deployUse /tmp only for temporary clones or caches.
---
1. Resolve and analyze the repo
For Git URLs, clone to a temporary cache. For local paths, analyze in place.
input="${1:-.}"
if [[ "$input" =~ ^(https?|git@) ]]; then
repo_name=$(basename "$input" .git)
cache_dir="/tmp/volcengine-prepare/$repo_name"
mkdir -p "$cache_dir"
[ -d "$cache_dir/src/.git" ] || git clone --depth 1 "$input" "$cache_dir/src"
repo_dir="$cache_dir/src"
else
repo_dir=$(cd "$input" && pwd)
repo_name=$(basename "$repo_dir")
fi
git_sha=$(cd "$repo_dir" && git rev-parse --short HEAD 2>/dev/null || echo "unversioned")Run:
skill_dir="$(dirname "$0")" # or the path to this skill
analysis=$(bash "$skill_dir/scripts/analyze-repo.sh" "$repo_dir")
echo "$analysis" | jq .Show the important findings in plain language:
Project: <repo_name> @ <git_sha>
Runtime: <language> / <framework>
Deployable subdir: <deploy_subdir or repo root>
Deployable surface: <web service | rpc service | http api | static/html site | full-stack app | user-specified service | unclear>
Entrypoint: <entrypoint>
Port: <port>
Packaging signals: Dockerfile=<yes/no>, compose=<yes/no if detected>
Dependencies: <mysql, redis, ...>
Migrations: <paths or none>If the analyzer cannot identify a concrete ECS/VKE/veFaaS deploy target, ask what subdirectory, service, command, artifact, static output, or existing veFaaS app/function should be deployed before recommending a path. Downgrade to confirmation instead of a strong recommendation when the repo appears to be primarily build tooling, packaging, examples, docs, or reusable code rather than an application surface.
A deploy target is something that can be run, containerized, exposed, or served by ECS, VKE, or veFaaS. Useful evidence includes, but is not limited to:
- a long-running process with a start command,
- a listening port or RPC/API/HTTP route,
- a static/HTML site entry or build output intended for serving,
- a health check or smoke endpoint,
- frontend and backend/API pieces with a clear service boundary,
- an explicit user instruction naming the service, subdirectory, command, artifact, or runtime target.
Do not infer deployability from a Dockerfile, package scripts, or build tooling alone.
---
2. Optional cloud identity check
If VOLCENGINE_ACCESS_KEY, VOLCENGINE_SECRET_KEY, and VOLCENGINE_REGION are set, verify identity:
ve sts GetCallerIdentityDo not read ~/.volcengine/config.json; it may contain secrets. If env vars are absent, keep the recommendation going and tell the user credential checks will happen when executing the chosen path.
If cloud service availability matters for a near-term choice, run the read-only probe:
services=$(bash "$skill_dir/scripts/check-region-services.sh")
echo "$services" | jq .Surface permission or region notes in the corresponding option; do not hide that option.
Prechecks are advisory, not gates. If you can cheaply check quotas or permissions, present the result as a risk:
<quota/permission> may be insufficient; continuing could fail when creating resources. Proceed anyway?If account real-name verification or balance cannot be queried reliably, give a short reminder instead of inventing a check:
Creating cloud resources may require a real-name-verified account with sufficient balance/credit; if creation fails, resolve the account status in the console first.---
3. Recommend deployment paths
Use `references/deploy-mode-heuristics.md` for the detailed decision rules. Present a ranked list, not recommended=true/false flags or scoring internals. If the deployable surface is unclear, present the ambiguity first and ask the smallest follow-up question before ranking.
Include every materially viable option; do not force a full ECS / VKE / veFaaS comparison when the repo or user request clearly rules a path out. Mention a non-viable path only when its exclusion helps the user decide.
- ECS: VM path. Best for targets that can run on a Linux VM, such as Web/API/RPC services, full-stack apps, static-site serving processes, binaries, Docker/compose apps, workers, scheduled commands, or apps needing OS/network/disk/debugging control.
- VKE: Container/Kubernetes path. Best for containerized or Kubernetes-shaped targets, such as multi-service apps, Web/API/RPC containers, workers, Jobs/CronJobs, rolling updates, replicas, HPA, Ingress/Service, GPU workloads, or production container operations.
- veFaaS: Serverless path. Best only when the target fits the
volcengine-vefaasskill workflow: supported Web/API or frontend/static frameworks, or an existing veFaaS app/function. Prefer ECS/VKE for long-running workers, multi-service orchestration, complex migrations, unsupported event/task/trigger creation, custom system dependencies, or no available API Gateway. If the user chooses it, switch to/call thevolcengine-vefaasskill for deployment; if that fails, return to the main flow so the user can retry or choose ECS/VKE.
Include:
- why it is ranked where it is
- rough cost level (
low,medium,medium-high) - operational tradeoffs
- known blockers or setup needed if the user chooses it
- resource management recommendation (
iacorcli) and why
Do not check every tool before the user chooses. Phrase setup needs as decision guidance:
Resource management needs user confirmation: recommend Terraform/volcenginecc for VKE, managed database/cache/storage/LB/domain/certificate, or long-lived team resources; recommend the ve CLI fast path (record a resource ledger) for plain single-VM ECS, temporary validation, or when Terraform / the provider registry is unavailable.
Choosing VKE will check kubectl; if you choose IaC it will also check terraform/provider availability.
Choosing veFaaS switches to / calls the `volcengine-vefaas` skill to check the vefaas CLI, login status, and framework detection; on failure it returns here so you can fix it and retry, or switch to ECS/VKE.---
4. Ask only necessary questions
After showing the ranked list, ask only what cannot be safely inferred:
1. Deployment mode: defaults to the top-ranked option. Choose ECS / VKE / veFaaS (recorded as `ecs` / `vke` / `vefaas`).
2. Resource strategy: defaults to a new isolated project deploy-<repo> with new resources; you may also reuse existing resources.
3. Database product/engine, only when a managed database is detected or requested: choose `rds/mysql`, `rds/postgresql`, `rds/sqlserver`, `aidap/supabase`, or `aidap/postgresql`.
4. Resource management: recommend <cli|iac>; confirm whether to use the CLI resource ledger or Terraform/IaC.For MySQL dependencies, use database_product=rds and database_engine=mysql unless the user rejects managed RDS. For SQL Server dependencies, use database_product=rds and database_engine=sqlserver. For PostgreSQL dependencies, preserve explicit user intent first: choose RDS PostgreSQL for an explicit RDS / managed RDS instance request, choose AIDAP PostgreSQL for an explicit AIDAP/serverless PostgreSQL request, and choose AIDAP Supabase for an explicit Supabase request. When the product is ambiguous and the user has not delegated the choice, ask because RDS PostgreSQL, AIDAP PostgreSQL, and AIDAP Supabase are different choices.
Ask whether to use Terraform/IaC explicitly. Give a recommendation, but do not turn it into a default:
Resource management recommendation: choose Terraform/volcenginecc for VKE, managed dependencies, long-lived team resources, or when you need plan/diff/destroy; choose the ve CLI fast path (record a resource ledger) for plain single-VM ECS, a temporary demo, or when Terraform / the provider registry is unavailable. Confirm `iac` or `cli`.If the user says "you decide", use:
- deployment mode: first ranked option
- resources: create new isolated Volcengine project
deploy-<repo> - database product/engine: infer exact engines when unambiguous (
mysql->rds/mysql,sqlserver->rds/sqlserver); for PostgreSQL, choose AIDAP Supabase (database_product=aidap,database_engine=supabase) when the project has no explicit RDS/AIDAP PostgreSQL/Supabase signal. - resource management: apply the table in `references/deploy-mode-heuristics.md`: plain ECS single-VM without managed dependencies can be
cli; VKE, managed dependencies, team-owned infrastructure, or plan/diff/destroy needs areiac
If the user chooses reuse, ask for only the resource IDs needed by that path. Reused resources must not be destroyed by cleanup.
---
5. Persist the user's choice only when useful
If execution continues in the same conversation, no file is required. If the user may resume later or the next step needs a durable handoff, write only a small choice record:
{
"schema_version": "1",
"repo_dir": "/absolute/path",
"repo_name": "my-app",
"git_sha": "abc1234",
"region": "cn-beijing",
"mode": "ecs",
"port": 8080,
"dependencies": ["postgresql", "redis"],
"database_product": "aidap",
"database_engine": "supabase",
"resource_strategy": "create-isolated-project",
"project": "deploy-my-app",
"infra_management": "cli"
}Write it to .volcengine/deploy-choice.json.
Do not write score tables, rationale arrays, or a full recommendation matrix unless the user asks for a report.
---
6. Summary template
Project detection:
- Runtime: <language>/<framework>
- Deployable surface: <surface or unclear, with evidence>
- Entrypoint/port: <entrypoint> / <port>
- Packaging signals: Dockerfile=<yes/no>, Compose=<yes/no>
- Dependencies: <deps or none>
- Database choice: <none | database_product=rds engine=mysql|postgresql|sqlserver | database_product=aidap engine=supabase|postgresql>
- Migrations: <paths or none>
- Resource management recommendation: <iac|cli> (VKE/managed dependencies/team resources usually suggest iac; plain single-VM ECS or unavailable IaC usually suggests cli)
Ranked order:
1. <mode>
Reason: ...
Tradeoff: ...
Rough cost: ...
2. <mode>
...
3. <mode>
...
Please confirm:
1. Deployment mode: defaults to <first mode>
2. Resource strategy: defaults to a new isolated project deploy-<repo>; reuse is also possible
3. Resource management: recommend <iac|cli>; confirm `iac` or `cli`Deploy Mode Heuristics
Use this when volcengine-prepare explains ECS / VKE / veFaaS choices. The output is a ranked recommendation for the user, not a score table and not a filter. Show every materially viable path, pick a default deployment mode when the deploy target is clear, and ask for lifecycle, reuse, and resource-management choices. Use ecs | vke | vefaas as machine-readable mode values.
Ranking rules
Rank by deployable service surface first. Do not demote a path just because a local tool is missing; tool checks happen after the user chooses.
If analysis reports deploy_subdir, rank the app in that subdirectory. Only treat a repo or subdirectory as deployable when there is a concrete target: the repo, subdirectory, command, artifact, static output, or existing cloud app/function that a path can actually run, containerize, expose, or serve.
File and framework signals are only evidence. A Dockerfile, compose file, package.json, framework dependency, or build/dev/test script does not by itself mean the repo is deployable.
Before ranking, identify whether there is a concrete deploy target for ECS, VKE, or veFaaS: something that can be run, containerized, exposed, or served by one of those paths.
Useful evidence includes, but is not limited to: a long-running process, start command, listening port, RPC/API/HTTP route, health/smoke endpoint, static/frontend build output intended to be served, clear frontend/backend service boundaries, existing veFaaS app/function, or a user-provided subdirectory, service, command, artifact, or runtime target.
If the surface is unclear, ask one focused follow-up before giving a strong recommendation:
I can see build/package signals, but not the deploy target yet. Which subdirectory, service, command, artifact, static output, or existing veFaaS app/function should be deployed?Use this downgrade path for repos that look like a library/SDK, CLI tool, agent skill, plugin, desktop app, tutorial/demo fragment, documentation-only project, or monorepo root without a selected app. These repos are not ECS/VKE/veFaaS deployment targets by default. If the user explicitly asks to deploy one, continue by identifying the concrete runtime surface, such as a docs site, example app, demo API, service command, static build output, or artifact to run; do not reject the request just because of the repo category.
Prefer ECS when
- The user wants the fastest path to a public URL.
- The deployable surface can run on a Linux VM as a Web/API/RPC service, full-stack app, static-site serving process, binary, Docker/compose app, worker, or scheduled command.
- The project is simple enough for one VM or a small number of VMs.
- The repo has external dependencies but the selected service does not need Kubernetes-level rollout, autoscaling, or multi-service orchestration.
- The app needs OS, network, disk, package, or debugging control.
- The user needs a quick validation, fastest public URL, or one-VM shape. For resource management, recommend CLI for pure ECS single-VM deployments, especially when Terraform or provider registry access is unavailable. Recommend IaC for ECS when it is team-managed, needs managed dependencies, or needs plan/diff/destroy safety.
ECS packaging:
| Signal | Packaging |
|---|---|
compose.yaml / compose.yml / docker-compose.yml / docker-compose.yaml exists | ecs-compose |
| Dockerfile exists | ecs-docker |
| Go / Rust / Java / .NET or clear single-process app | binary-systemd |
| Unclear app start but can be containerized | ask one follow-up for start command or Dockerfile choice |
Explain the default ECS shape:
- It creates or reuses an ECS instance.
- New public services get an EIP as the access endpoint.
- Ask the user whether to open SSH 22. If they do not want SSH, deploy and debug through Cloud Assistant.
- Approximate cost:
medium(ECS instance + system disk + EIP/bandwidth; plus any managed dependencies).
Prefer VKE when
- The selected deployable surface is containerized or naturally maps to Kubernetes workloads.
- The app needs multiple replicas, rolling updates, HPA, Kubernetes Jobs/CronJobs, Ingress/Service, or network policies.
- The selected app has multiple services, multiple languages, or several long-running processes.
- Migrations or workers need a cleaner lifecycle than a single systemd service.
- The workload needs GPU resources or production container operations.
- The user wants a production-shaped container platform.
Recommend Terraform/volcenginecc for VKE resource creation because clusters, node pools, CR, LB, and managed dependencies benefit from plan/diff/destroy safety. Use ve CLI plus .volcengine/created-resources.json only if the user chooses CLI after seeing the tradeoff, for temporary validation, or when Terraform is unavailable.
Approximate cost: medium-high (VKE nodes + CR + CLB/EIP + bandwidth; plus databases/cache/storage).
Prefer veFaaS when
- The target fits the
volcengine-vefaasskill workflow: a supported Web/API framework, supported frontend/static framework, or an existing veFaaS app/function. - The target is an MCP project and does not have a user-mandated ECS runtime. For MCP, rank veFaaS first, ECS second, and do not recommend VKE by default because this workflow needs session keeping.
- There are no complex in-band DB migrations, long-running workers, multi-service orchestration needs, unsupported event/task/trigger creation, custom system dependencies, or API Gateway blockers.
- The framework is likely supported by the
volcengine-vefaasskill, such as FastAPI, Django, Flask, Express, Next.js, Nuxt, NestJS, Remix, Vite, Astro, Vitepress, Rspress, Create React App, or Angular. - Low operational overhead and pay-by-use economics matter more than infrastructure control.
If the user chooses veFaaS, switch to/call the volcengine-vefaas skill. If it fails, return to the main deployment flow and let the user retry veFaaS or switch to ECS/VKE. Do not use the legacy ZIP/API flow in volcengine-deploy.
For MCP projects, use volcengine-vefaas/references/mcp-deployment.md after selecting veFaaS. VKE is only appropriate when the user explicitly asks for Kubernetes and already has a session-affinity plan.
Approximate cost: low-medium (function resources + API Gateway; plus dependency services if used).
Common warning signals
Mention these in the relevant option, but do not hide the option:
| Signal | What to tell the user |
|---|---|
| Dockerfile but no long-running process, port, route, static output, or user-specified start command | Dockerfile is packaging evidence, not deployability. Ask which service or artifact should be run. |
| Dockerfile references missing scripts or placeholder server packages | Treat the Dockerfile as stale or incomplete. Do not recommend ECS/VKE until a working build command and runtime entrypoint are confirmed. |
package.json only has build/dev/test-like scripts | Build tooling is not a service contract. Ask whether this is a frontend site, full-stack app, API service, library, or tooling package. |
| README or runtime docs give an official port, route, or deploy command | Prefer those docs over default guesses, then verify with a smoke check after deployment. |
| Monorepo root with multiple candidates | Ask for the app/subdir to deploy before ranking. |
| Library/SDK/CLI/desktop/tutorial/docs-like repo | Downgrade to manual confirmation; ask what online service or site should be exposed. |
migration_paths non-empty | veFaaS may need a separate migration step; VKE can run a Job, ECS can run a one-shot command. |
| WebSocket / long-lived connections | ECS or VKE is usually safer than veFaaS. |
| Compose file with Redis/MySQL/etc. | ECS compose can run it quickly, but data durability and scaling are weaker than managed services or VKE. |
| Many stateful dependencies | VKE or managed services may be more appropriate; ECS remains possible for quick validation. |
| External MySQL/PostgreSQL/SQL Server/Redis dependency | Recommend managed services with the same VPC, private endpoint, and explicit migration step. Use RDS for MySQL and SQL Server. For PostgreSQL, preserve explicit user intent; when ambiguous ask for RDS PostgreSQL, AIDAP PostgreSQL, or AIDAP Supabase, and if the user delegates the choice default to AIDAP Supabase. For Redis, use managed Redis by default. |
| Project only uses SQLite | Keep it as a valid choice; warn about single-node/disk durability, but do not imply RDS migration is required. |
| Long-lived cloud resources | Recommend IaC for VKE, managed dependencies, team-owned infrastructure, or plan/diff/destroy needs. Recommend CLI for pure ECS single-VM services when speed and fewer dependencies matter more. |
| Static frontend | veFaaS/static serving may be possible, but ECS/VKE are still valid if the user wants one service shape. |
| Unknown port or start command | Ask one concise follow-up after the user chooses a path. |
| Region/service permission notes | Surface them next to the affected path and let the user decide. |
Suggested recommendation patterns
Go API with Redis, no Dockerfile
1. ECS
- Reason: compiled service can run directly under systemd; Redis can be managed or run via compose for quick validation.
- Tradeoff: single-VM operation unless expanded later.
2. VKE
- Reason: good if the user wants replicas, rolling rollout, or managed Redis wiring.
- Tradeoff: more resources and setup.
3. veFaaS
- Reason: low ops if the app is stateless.
- Warning: Redis and any migration/worker behavior must be confirmed.
Existing Dockerfile plus database migrations
1. VKE
- Reason: containerized app and migrations map cleanly to Deployment + Job.
2. ECS
- Reason: simpler if one VM is enough; run Docker or compose on ECS.
3. veFaaS
- Warning: migrations need a separate plan and framework support must be verified by
volcengine-vefaas; failure should return to the main flow for retry or ECS/VKE selection.
FastAPI / Next.js with no external dependencies
1. veFaaS
- Reason: supported framework shape, low ops, pay-by-use.
2. ECS
- Reason: fastest predictable VM path with EIP.
3. VKE
- Reason: valid but heavier unless the user wants Kubernetes.
MCP project
1. veFaaS
- Reason: default MCP path for HTTP exposure and session keeping.
2. ECS
- Reason: fallback when veFaaS does not fit the runtime, dependency installation, or system-control needs.
3. VKE
- Warning: not a default MCP path; use only when the user explicitly asks for Kubernetes and already has a session-affinity plan.
Resource management recommendation
Recommend resource management, then ask the user to choose:
| Signal | Resource management |
|---|---|
| User says "temporary", "demo", "quick validation", or "just run it" | cli fast path with .volcengine/created-resources.json |
| Pure ECS single-VM service with no managed dependencies and no explicit plan/diff/destroy requirement | cli fast path with .volcengine/created-resources.json |
| Any VKE, managed DB/cache/storage/LB/domain/certificate, or team-owned service | iac |
| User needs plan/diff/drift/destroy or may resume later | iac |
| Terraform/provider/network unavailable and the user accepts lower reproducibility | cli fallback |
| User explicitly says "no Terraform/IaC" | cli |
For China network conditions, include a note when Docker images are involved: Docker Hub and GHCR may be slow or blocked. Deployment should prefer Volcengine CR, user-provided registries, or an inspected domestic mirror/sync URL over direct public registry pulls.
User confirmation
After presenting the ranked list, ask only:
1. Deployment mode: defaults to the top-ranked option. Choose ECS / VKE / veFaaS (recorded as `ecs` / `vke` / `vefaas`).
2. Resource strategy: defaults to a new isolated project deploy-<repo> with new resources; you may also reuse existing resources.
3. Resource management: recommend <cli|iac>; confirm whether to use the CLI resource ledger or Terraform/IaC.Mention the resource management recommendation, then ask for confirmation:
Resource management recommendation: choose Terraform/volcenginecc for VKE, managed dependencies, and team resources; choose the ve CLI fast path (record a resource ledger) for plain single-VM ECS, temporary validation, or when IaC is unavailable. Confirm `iac` or `cli`.#!/usr/bin/env bash
# Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd.
# SPDX-License-Identifier: MIT
# analyze-repo.sh — Analyze a project directory: language, framework, port,
# runtime dependencies, migration paths, entrypoint. Output JSON to stdout.
#
# Usage: bash analyze-repo.sh <repo-directory>
# Exit non-zero only on hard errors (missing dir). Unknown values become
# "unknown"/empty arrays so downstream agents can keep moving.
set -euo pipefail
repo_dir="${1:-.}"
if [ ! -d "$repo_dir" ]; then
echo "{\"error\": \"Directory not found: ${repo_dir}\"}"
exit 1
fi
cd "$repo_dir"
# ---------- helpers ----------
# Build a JSON array literal from positional args. Empty -> [].
json_array() {
local items=("$@")
if [ ${#items[@]} -eq 0 ]; then
echo "[]"
return
fi
local result="["
local i
for i in "${!items[@]}"; do
[ "$i" -gt 0 ] && result+=","
result+="\"${items[$i]}\""
done
result+="]"
echo "$result"
}
# Glob expansion safe inside `if`. Returns 0 if pattern matches any file/dir.
has_glob() {
local pattern="$1"
[ -n "$(find . -maxdepth 2 -name "$pattern" 2>/dev/null | head -1)" ]
}
detect_compose_file() {
for f in compose.yaml compose.yml docker-compose.yaml docker-compose.yml; do
[ -f "$f" ] && echo "$f" && return
done
echo ""
}
detect_compose_file_in_dir() {
local dir="$1"
for f in compose.yaml compose.yml docker-compose.yaml docker-compose.yml; do
[ -f "$dir/$f" ] && echo "$f" && return
done
echo ""
}
is_deployable_dir() {
local dir="$1"
[ -f "$dir/Dockerfile" ] && return 0
[ -n "$(detect_compose_file_in_dir "$dir")" ] && return 0
if [ -f "$dir/package.json" ]; then
if grep -qE '"(start|dev|build|serve|preview)"[[:space:]]*:' "$dir/package.json"; then
return 0
fi
fi
if [ -f "$dir/bun.lock" ] || [ -f "$dir/bun.lockb" ] || [ -f "$dir/deno.json" ] || [ -f "$dir/deno.jsonc" ]; then
return 0
fi
if [ -f "$dir/go.mod" ] && { [ -f "$dir/main.go" ] || [ -d "$dir/cmd" ]; }; then
return 0
fi
if [ -f "$dir/requirements.txt" ] || [ -f "$dir/pyproject.toml" ] || [ -f "$dir/setup.py" ]; then
if [ -f "$dir/main.py" ] || [ -f "$dir/app.py" ] || [ -f "$dir/manage.py" ] ||
[ -f "$dir/wsgi.py" ] || [ -f "$dir/asgi.py" ] || [ -d "$dir/src" ]; then
return 0
fi
fi
if [ -f "$dir/pom.xml" ] || [ -f "$dir/build.gradle" ] || [ -f "$dir/build.gradle.kts" ]; then
return 0
fi
if [ -f "$dir/Cargo.toml" ] && [ -f "$dir/src/main.rs" ]; then
return 0
fi
if [ -f "$dir/Gemfile" ] && { [ -f "$dir/config.ru" ] || [ -f "$dir/app.rb" ] || [ -d "$dir/bin" ]; }; then
return 0
fi
if [ -f "$dir/composer.json" ] && { [ -f "$dir/public/index.php" ] || [ -f "$dir/index.php" ]; }; then
return 0
fi
find "$dir" -maxdepth 1 \( -name "*.csproj" -o -name "*.sln" \) 2>/dev/null | grep -q . && return 0
return 1
}
detect_deploy_subdir() {
is_deployable_dir "." && { echo "."; return; }
local candidates=(site web app apps frontend backend server api homepage)
local dir
for dir in "${candidates[@]}"; do
[ -d "$dir" ] && is_deployable_dir "$dir" && { echo "$dir"; return; }
done
while IFS= read -r dir; do
is_deployable_dir "$dir" && { echo "${dir#./}"; return; }
done < <(find packages apps services -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort)
echo ""
}
# ---------- language detection ----------
# Order matters: Bun/Deno take priority over Node since they may coexist
# with package.json but use different runtimes. PHP added.
detect_language() {
if [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then echo "bun"
elif [ -f "deno.json" ] || [ -f "deno.jsonc" ] || [ -f "deno.lock" ]; then echo "deno"
elif [ -f "package.json" ]; then echo "nodejs"
elif [ -f "go.mod" ]; then echo "go"
elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ] || [ -f "setup.py" ]; then echo "python"
elif [ -f "pom.xml" ] || [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then echo "java"
elif [ -f "Cargo.toml" ]; then echo "rust"
elif [ -f "Gemfile" ]; then echo "ruby"
elif [ -f "composer.json" ]; then echo "php"
elif has_glob "*.csproj" || has_glob "*.sln"; then echo "dotnet"
elif [ -f "mix.exs" ]; then echo "elixir"
else echo "unknown"
fi
}
# ---------- framework detection ----------
detect_framework() {
local lang="$1"
case "$lang" in
nodejs|bun|deno)
local deps=""
[ -f "package.json" ] && deps=$(cat package.json)
[ -f "deno.json" ] && deps="$deps $(cat deno.json)"
if echo "$deps" | grep -q '"@nestjs/core"'; then echo "nestjs"
elif echo "$deps" | grep -q '"next"'; then echo "nextjs"
elif echo "$deps" | grep -q '"express"'; then echo "express"
elif echo "$deps" | grep -q '"fastify"'; then echo "fastify"
elif echo "$deps" | grep -q '"koa"'; then echo "koa"
elif echo "$deps" | grep -q '"hono"'; then echo "hono"
elif echo "$deps" | grep -q '"oak"'; then echo "oak"
else echo "unknown"
fi
;;
python)
local all_deps=""
[ -f "requirements.txt" ] && all_deps=$(cat requirements.txt)
[ -f "pyproject.toml" ] && all_deps="$all_deps $(cat pyproject.toml)"
if echo "$all_deps" | grep -qi "fastapi"; then echo "fastapi"
elif echo "$all_deps" | grep -qi "django"; then echo "django"
elif echo "$all_deps" | grep -qi "flask"; then echo "flask"
elif echo "$all_deps" | grep -qi "tornado"; then echo "tornado"
elif echo "$all_deps" | grep -qi "sanic"; then echo "sanic"
else echo "unknown"
fi
;;
go)
if [ -f "go.mod" ]; then
local mods
mods=$(cat go.mod)
if echo "$mods" | grep -q "gin-gonic"; then echo "gin"
elif echo "$mods" | grep -q "labstack/echo"; then echo "echo"
elif echo "$mods" | grep -q "gofiber/fiber"; then echo "fiber"
elif echo "$mods" | grep -q "go-chi/chi"; then echo "chi"
elif echo "$mods" | grep -q "gorilla/mux"; then echo "gorilla"
else echo "unknown"
fi
fi
;;
java)
local build_file=""
[ -f "pom.xml" ] && build_file=$(cat pom.xml)
[ -f "build.gradle" ] && build_file="$build_file $(cat build.gradle)"
[ -f "build.gradle.kts" ] && build_file="$build_file $(cat build.gradle.kts)"
if echo "$build_file" | grep -qi "spring-boot"; then echo "spring-boot"
elif echo "$build_file" | grep -qi "quarkus"; then echo "quarkus"
elif echo "$build_file" | grep -qi "micronaut"; then echo "micronaut"
else echo "unknown"
fi
;;
rust)
if [ -f "Cargo.toml" ]; then
local cargo
cargo=$(cat Cargo.toml)
if echo "$cargo" | grep -q "actix-web"; then echo "actix"
elif echo "$cargo" | grep -q "axum"; then echo "axum"
elif echo "$cargo" | grep -q "rocket"; then echo "rocket"
elif echo "$cargo" | grep -q "warp"; then echo "warp"
else echo "unknown"
fi
fi
;;
ruby)
if [ -f "Gemfile" ]; then
if grep -q "rails" Gemfile; then echo "rails"
elif grep -q "sinatra" Gemfile; then echo "sinatra"
else echo "unknown"
fi
fi
;;
php)
if [ -f "composer.json" ]; then
local composer
composer=$(cat composer.json)
if echo "$composer" | grep -q "laravel/framework"; then echo "laravel"
elif echo "$composer" | grep -q "symfony/symfony\|symfony/framework-bundle"; then echo "symfony"
elif echo "$composer" | grep -q "slim/slim"; then echo "slim"
else echo "unknown"
fi
fi
;;
*) echo "unknown" ;;
esac
}
# ---------- port detection ----------
detect_port() {
local port=""
# Dockerfile EXPOSE
if [ -f "Dockerfile" ]; then
port=$(grep -i "^EXPOSE" Dockerfile 2>/dev/null | head -1 | grep -oE '[0-9]+' | head -1)
[ -n "$port" ] && echo "$port" && return
fi
# docker-compose ports
local compose_file
compose_file=$(detect_compose_file)
if [ -n "$compose_file" ]; then
port=$(grep -E 'ports:' -A 5 "$compose_file" 2>/dev/null | grep -oE '[0-9]+:[0-9]+' | head -1 | cut -d: -f2)
[ -n "$port" ] && echo "$port" && return
fi
# Source code scan: widened from depth 3/30 files to depth 5/100 files
local all_code=""
while IFS= read -r f; do
all_code="$all_code $(cat "$f" 2>/dev/null || true)"
done < <(find . -maxdepth 5 \( -name "*.js" -o -name "*.ts" -o -name "*.py" \
-o -name "*.go" -o -name "*.java" -o -name "*.rs" -o -name "*.rb" -o -name "*.php" \
-o -name "*.env" -o -name "*.env.example" \
-o -name "application.yml" -o -name "application.properties" \) 2>/dev/null | head -100)
port=$(echo "$all_code" | grep -oiE 'port\s*[=:]\s*[0-9]+' | grep -oE '[0-9]+' | head -1)
[ -n "$port" ] && echo "$port" && return
# Framework default fallback
local lang
lang=$(detect_language)
case "$lang" in
nodejs|bun|deno) echo "3000" ;;
python) echo "8000" ;;
go) echo "8080" ;;
java) echo "8080" ;;
rust) echo "8080" ;;
ruby) echo "3000" ;;
php) echo "8000" ;;
dotnet) echo "5000" ;;
*) echo "8080" ;;
esac
}
# ---------- runtime dependency detection ----------
detect_dependencies() {
local deps=()
local search_content=""
# Config files
for f in compose.yaml compose.yml docker-compose.yml docker-compose.yaml .env .env.example \
.env.sample config.yml config.yaml application.yml application.properties \
appsettings.json; do
[ -f "$f" ] && search_content="$search_content $(cat "$f" 2>/dev/null || true)"
done
# Manifest files
for f in package.json go.mod requirements.txt pyproject.toml pom.xml \
build.gradle build.gradle.kts Cargo.toml Gemfile composer.json deno.json; do
[ -f "$f" ] && search_content="$search_content $(cat "$f" 2>/dev/null || true)"
done
# Source scan: depth 5 / 100 files (was depth 4 / 30)
while IFS= read -r f; do
search_content="$search_content $(cat "$f" 2>/dev/null || true)"
done < <(find . -maxdepth 5 \( -name "*.js" -o -name "*.ts" -o -name "*.py" \
-o -name "*.go" -o -name "*.java" -o -name "*.rs" -o -name "*.rb" -o -name "*.php" \) \
2>/dev/null | head -100)
if echo "$search_content" | grep -qiE 'mysql|mysql2|mysqlclient|pymysql|jdbc:mysql|:3306'; then
deps+=("mysql")
fi
if echo "$search_content" | grep -qiE 'postgres|postgresql|psycopg|pg-promise|jdbc:postgresql|:5432'; then
deps+=("postgresql")
fi
if echo "$search_content" | grep -qiE 'redis|ioredis|redis-py|bull|:6379'; then
deps+=("redis")
fi
if echo "$search_content" | grep -qiE 'mongodb|mongoose|pymongo|mongoclient|:27017'; then
deps+=("mongodb")
fi
if echo "$search_content" | grep -qiE 'kafka|kafkajs|kafka-python|confluent.kafka|:9092'; then
deps+=("kafka")
fi
if echo "$search_content" | grep -qiE 'rabbitmq|amqplib|amqp|pika|:5672'; then
deps+=("rabbitmq")
fi
# Memcached (new)
if echo "$search_content" | grep -qiE 'memcache|memcached|pymemcache|:11211'; then
deps+=("memcached")
fi
# ClickHouse (new) — bare keyword catches drivers and class references
if echo "$search_content" | grep -qiE 'clickhouse|:8123'; then
deps+=("clickhouse")
fi
if echo "$search_content" | grep -qiE 'elasticsearch|@elastic|opensearch|:9200'; then
deps+=("elasticsearch")
fi
# Volcengine TOS
if echo "$search_content" | grep -qiE '@volcengine/tos|tos-sdk|tos\.volces\.com|TOS_BUCKET|VOLCENGINE_TOS'; then
deps+=("tos")
fi
# Object storage compatibility signals.
# Skip if TOS already detected (TOS is the preferred Volcengine equivalent).
local has_tos=false
local d
for d in ${deps[@]+"${deps[@]}"}; do
[ "$d" = "tos" ] && has_tos=true && break
done
if [ "$has_tos" = false ]; then
if echo "$search_content" | grep -qiE 'minio|MINIO_ENDPOINT|s3cmd|minio-py|boto3'; then
deps+=("s3-compatible")
fi
fi
json_array ${deps[@]+"${deps[@]}"}
}
# ---------- migration detection ----------
detect_migration() {
local migration_paths=()
for dir in migrations db/migrate prisma alembic flyway src/main/resources/db/migration \
database/migrations knex/migrations sql; do
[ -d "$dir" ] && migration_paths+=("$dir")
done
[ -f "prisma/schema.prisma" ] && migration_paths+=("prisma/schema.prisma")
for f in init.sql schema.sql setup.sql; do
[ -f "$f" ] && migration_paths+=("$f")
done
json_array ${migration_paths[@]+"${migration_paths[@]}"}
}
# ---------- Dockerfile presence ----------
has_dockerfile() {
[ -f "Dockerfile" ] && echo "true" || echo "false"
}
has_compose() {
[ -n "$(detect_compose_file)" ] && echo "true" || echo "false"
}
# ---------- entrypoint detection ----------
detect_entrypoint() {
local lang="$1"
case "$lang" in
nodejs|bun|deno)
if [ -f "package.json" ]; then
local main
main=$(grep -oE '"main"\s*:\s*"[^"]+"' package.json 2>/dev/null \
| grep -oE '"[^"]+"\s*$' | tr -d '"' | xargs || true)
[ -n "$main" ] && echo "$main" && return
local start_script
start_script=$(grep -oE '"start"\s*:\s*"[^"]+"' package.json 2>/dev/null | head -1)
[ -n "$start_script" ] && echo "npm start" && return
fi
for f in src/index.ts src/main.ts src/server.ts src/app.ts index.ts \
src/index.js src/main.js src/server.js src/app.js index.js server.js app.js \
main.ts mod.ts; do
[ -f "$f" ] && echo "$f" && return
done
;;
python)
for f in main.py app.py manage.py src/main.py src/app.py wsgi.py asgi.py; do
[ -f "$f" ] && echo "$f" && return
done
;;
go)
[ -d "cmd" ] && echo "cmd/" && return
[ -f "main.go" ] && echo "main.go" && return
;;
java)
local main_class
main_class=$(find . -maxdepth 6 -name "*.java" \
-exec grep -l "public static void main" {} \; 2>/dev/null | head -1)
[ -n "$main_class" ] && echo "$main_class" && return
[ -f "pom.xml" ] && echo "pom.xml (Maven)" && return
[ -f "build.gradle" ] && echo "build.gradle (Gradle)" && return
;;
rust)
[ -f "src/main.rs" ] && echo "src/main.rs" && return
;;
ruby)
[ -f "config.ru" ] && echo "config.ru" && return
[ -f "app.rb" ] && echo "app.rb" && return
;;
php)
[ -f "public/index.php" ] && echo "public/index.php" && return
[ -f "index.php" ] && echo "index.php" && return
;;
dotnet)
local proj
proj=$(find . -maxdepth 2 -name "*.csproj" 2>/dev/null | head -1)
[ -n "$proj" ] && echo "$proj" && return
;;
esac
echo "unknown"
}
# ---------- main ----------
repo_root=$(pwd)
deploy_subdir=$(detect_deploy_subdir)
analysis_dir="$repo_root"
if [ -n "$deploy_subdir" ] && [ "$deploy_subdir" != "." ]; then
analysis_dir="$repo_root/$deploy_subdir"
cd "$analysis_dir"
fi
language=$(detect_language)
framework=$(detect_framework "$language")
port=$(detect_port)
has_dockerfile=$(has_dockerfile)
has_compose=$(has_compose)
compose_file=$(detect_compose_file)
dependencies=$(detect_dependencies)
migration=$(detect_migration)
entrypoint=$(detect_entrypoint "$language")
runnable=$([ -n "$deploy_subdir" ] && echo "true" || echo "false")
cat <<EOF
{
"repo_dir": "$repo_dir",
"deploy_subdir": "$deploy_subdir",
"language": "$language",
"framework": "$framework",
"port": "$port",
"has_dockerfile": $has_dockerfile,
"has_compose": $has_compose,
"compose_file": "$compose_file",
"entrypoint": "$entrypoint",
"dependencies": $dependencies,
"migration_paths": $migration,
"runnable": $runnable
}
EOF
#!/usr/bin/env bash
# Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd.
# SPDX-License-Identifier: MIT
# check-region-services.sh — Probe whether ECS / VKE / CR / veFaaS are
# available in the current $VOLCENGINE_REGION using the cheapest read-only API
# per service. Output JSON with four booleans and a list of probe failures.
#
# Strategy: run each probe, capture stdout+stderr, mark service as available
# unless the response carries an explicit "Service*Unavailable", "NotSupport",
# or auth/permission failure. Quota errors are treated as "service exists but
# limited" which still counts as available.
set -uo pipefail
region="${VOLCENGINE_REGION:-}"
if [ -z "$region" ]; then
echo '{"error": "VOLCENGINE_REGION is not set"}' >&2
exit 1
fi
if ! command -v ve >/dev/null 2>&1; then
echo '{"error": "ve CLI not found in PATH"}' >&2
exit 1
fi
# Run one probe; print "true" or "false" and capture failure reason.
# Args: <service-tag> <command...>
probe() {
local tag="$1"
shift
local out
out=$("$@" 2>&1) || true
# Definitive unavailable signals
if echo "$out" | grep -qiE 'ServiceNotAvailable|NotSupportedRegion|RegionNotSupported|NoSuchService|InvalidEndpoint|Failed to find endpoint'; then
echo "false|$tag: service not available in region"
return
fi
# Auth/permission failures prove the endpoint exists; record that access was denied.
if echo "$out" | grep -qiE 'Forbidden|UnauthorizedOperation|AccessDenied|NoPermission'; then
echo "true|$tag: endpoint responded but access was denied"
return
fi
# Quota errors — service exists, just no headroom
if echo "$out" | grep -qiE 'QuotaExceeded|LimitExceeded'; then
echo "true|$tag: quota limited (service available)"
return
fi
# Network or transport errors — inconclusive, default to false
if echo "$out" | grep -qiE 'connection refused|no such host|timeout'; then
echo "false|$tag: network error during probe"
return
fi
# Otherwise: presence of "ResponseMetadata" or absence of "Error" implies success
if echo "$out" | grep -q '"ResponseMetadata"' && ! echo "$out" | grep -q '"Error"'; then
echo "true|"
return
fi
# Fallback: any other unexpected error → mark unavailable for safety
local first_err
first_err=$(echo "$out" | grep -oE '"Code":"[^"]+"' | head -1 | tr -d '"' | sed 's/Code://')
echo "false|$tag: ${first_err:-unknown probe failure}"
}
# Probe each service. Order: ECS (always present) → CR → VKE → veFaaS.
ecs_result=$(probe "ecs" ve ecs DescribeAvailableResource \
--ZoneId "${region}-a" --DestinationResource InstanceType)
cr_result=$(probe "cr" ve cr ListRegistries --body '{"PageNumber":1,"PageSize":1}')
vke_result=$(probe "vke" ve vke ListClusters --body '{"PageNumber":1,"PageSize":1}')
faas_result=$(probe "vefaas" ve vefaas ListFunctions --body '{"PageNumber":1,"PageSize":1}')
ecs_ok="${ecs_result%%|*}"
cr_ok="${cr_result%%|*}"
vke_ok="${vke_result%%|*}"
faas_ok="${faas_result%%|*}"
notes=()
for r in "$ecs_result" "$cr_result" "$vke_result" "$faas_result"; do
msg="${r#*|}"
[ -n "$msg" ] && notes+=("$msg")
done
# Build notes JSON array
notes_json="["
for i in ${!notes[@]+"${!notes[@]}"}; do
[ "$i" -gt 0 ] && notes_json+=","
esc=${notes[$i]//\"/\\\"}
notes_json+="\"$esc\""
done
notes_json+="]"
cat <<EOF
{
"region": "$region",
"ecs_available": $ecs_ok,
"cr_available": $cr_ok,
"vke_available": $vke_ok,
"faas_available": $faas_ok,
"notes": $notes_json
}
EOF