feat: ship skill and MCP workflows with signed updater for v0.0.7

This commit is contained in:
xiaohan.yuan committed 2026-10-21 00:04:17 +08:00
1 parent 1b52df0603
commit a01085c656
136 files changed
+18646 -217

No files matched your search

+234
View File
@@ -0,0 +1,234 @@
import {
DEFAULT_SSH_HOST,
NGINX_MARKER,
NGINX_SITE_LINK,
NGINX_SNIPPET,
SERVER_PUBLIC_ROOT,
SERVER_RELEASES_ROOT,
SERVER_STAGING_ROOT,
parseOptions,
renderNoReleasePage,
runSsh,
usageError,
validateSshHost
} from './lib.mjs'
const usage = `Usage:
node scripts/updates/provision-server.mjs [--ssh-host local001]
Creates /srv/ycode, /srv/ycode/releases/versions and /srv/ycode-staging, backs up the
nginx site configuration, installs a YCode-only snippet, validates nginx, then reloads.
It never serves an index and never creates a fake latest.json.
`
const snippet = `${NGINX_MARKER}
location = /ycode/releases/latest.json {
alias ${SERVER_RELEASES_ROOT}/latest.json;
default_type application/json;
add_header Cache-Control "no-store" always;
add_header X-Content-Type-Options "nosniff" always;
limit_except GET { deny all; }
}
location = /ycode/releases/index.html {
alias ${SERVER_RELEASES_ROOT}/index.html;
default_type text/html;
charset utf-8;
add_header Cache-Control "no-store" always;
add_header X-Content-Type-Options "nosniff" always;
limit_except GET { deny all; }
}
location /ycode/ {
alias ${SERVER_PUBLIC_ROOT}/;
autoindex off;
index index.html;
add_header X-Content-Type-Options "nosniff" always;
limit_except GET { deny all; }
}
`
async function main() {
const options = parseOptions(process.argv.slice(2), { values: ['ssh-host'] })
const host = validateSshHost(options['ssh-host'] || DEFAULT_SSH_HOST)
const snippetBase64 = Buffer.from(snippet, 'utf8').toString('base64')
const noReleasePageBase64 = Buffer.from(renderNoReleasePage(), 'utf8').toString('base64')
const script = `set -euo pipefail
export LC_ALL=C
site_link='${NGINX_SITE_LINK}'
snippet='${NGINX_SNIPPET}'
site="$(readlink -f "$site_link")"
test -f "$site"
test -f /etc/nginx/nginx.conf
nginx -t >/dev/null 2>&1
install -d -o root -g www-data -m 0755 '${SERVER_PUBLIC_ROOT}'
install -d -o root -g www-data -m 0755 '${SERVER_RELEASES_ROOT}'
install -d -o root -g www-data -m 0755 '${SERVER_RELEASES_ROOT}/versions'
install -d -o root -g root -m 0700 '${SERVER_STAGING_ROOT}'
page_tmp="$(mktemp '${SERVER_RELEASES_ROOT}/.index.html.XXXXXX')"
printf '%s' '${noReleasePageBase64}' | base64 -d > "$page_tmp"
chmod 0644 "$page_tmp"
if [ -f '${SERVER_RELEASES_ROOT}/latest.json' ]; then
if [ ! -f '${SERVER_RELEASES_ROOT}/index.html' ]; then
rm -f "$page_tmp"
echo "latest.json exists without a generated download page" >&2
exit 1
fi
if grep -q 'data-ycode-state="no-release"' '${SERVER_RELEASES_ROOT}/index.html'; then
rm -f "$page_tmp"
echo "latest.json exists while the download page still says no release" >&2
exit 1
fi
rm -f "$page_tmp"
elif [ ! -f '${SERVER_RELEASES_ROOT}/index.html' ]; then
mv -f "$page_tmp" '${SERVER_RELEASES_ROOT}/index.html'
else
if ! grep -q 'data-ycode-state="no-release"' '${SERVER_RELEASES_ROOT}/index.html'; then
rm -f "$page_tmp"
echo "download page exists without latest.json" >&2
exit 1
fi
rm -f "$page_tmp"
fi
backup_dir=/var/backups/nginx
install -d -o root -g root -m 0700 "$backup_dir"
stamp="$(date -u +%Y%m%dT%H%M%SZ)"
config_backup="$backup_dir/ycode-before-${'$'}{stamp}-$(basename "$site")"
snippet_backup="$backup_dir/ycode-before-${'$'}{stamp}-ycode-releases.conf"
test ! -e "$config_backup"
cp -a "$site" "$config_backup"
snippet_existed=0
if [ -f "$snippet" ]; then
cp -a "$snippet" "$snippet_backup"
snippet_existed=1
fi
restore() {
changed=0
cp -a "$config_backup" "$site"
if [ "$snippet_existed" -eq 1 ]; then
cp -a "$snippet_backup" "$snippet"
else
rm -f "$snippet"
fi
}
changed=0
snippet_tmp=
cleanup() {
rc=$?
if [ -n "$snippet_tmp" ]; then
rm -f "$snippet_tmp"
fi
if [ "$rc" -ne 0 ] && [ "$changed" -eq 1 ]; then
restore
nginx -t >/dev/null 2>&1 && systemctl reload nginx >/dev/null 2>&1 || true
fi
exit "$rc"
}
trap cleanup EXIT
install -d -o root -g root -m 0755 /etc/nginx/snippets
snippet_tmp="$(mktemp /etc/nginx/snippets/.ycode-releases.XXXXXX)"
printf '%s' '${snippetBase64}' | base64 -d > "$snippet_tmp"
chmod 0644 "$snippet_tmp"
mv -f "$snippet_tmp" "$snippet"
changed=1
python3 - "$site" <<'PY'
import os
import re
import shutil
import sys
import tempfile
site = sys.argv[1]
marker = "${NGINX_MARKER}"
include = "\tinclude ${NGINX_SNIPPET};"
with open(site, "r", encoding="utf-8") as stream:
original = stream.read()
for required in ("location /baocode/ {", "location /baocode/releases/ {"):
if original.count(required) != 1:
raise SystemExit(f"refusing to change nginx: expected one {required}")
if marker in original:
if include not in original:
raise SystemExit("refusing to change nginx: YCode marker exists without include")
updated = original
else:
match = re.search(r"(?m)^([ \\t]*)location /baocode/ \\{", original)
if not match:
raise SystemExit("refusing to change nginx: baocode anchor not found")
indent = match.group(1)
insertion = f"{indent}{marker}\\n{indent}include ${NGINX_SNIPPET};\\n\\n"
updated = original[:match.start()] + insertion + original[match.start():]
if updated != original:
directory = os.path.dirname(site)
descriptor, temporary = tempfile.mkstemp(prefix=".ycode-nginx-", dir=directory)
try:
with os.fdopen(descriptor, "w", encoding="utf-8") as stream:
stream.write(updated)
stream.flush()
os.fsync(stream.fileno())
shutil.copystat(site, temporary)
os.replace(temporary, site)
finally:
if os.path.exists(temporary):
os.unlink(temporary)
with open(site, "r", encoding="utf-8") as stream:
final = stream.read()
for required in ("location /baocode/ {", "location /baocode/releases/ {"):
if final.count(required) != 1:
raise SystemExit("refusing to change nginx: baocode locations changed")
if marker not in final or include not in final:
raise SystemExit("nginx include was not installed")
PY
if ! nginx -t; then
echo "nginx validation failed; configuration restored" >&2
exit 1
fi
if ! systemctl reload nginx; then
echo "nginx reload failed; configuration restored" >&2
exit 1
fi
status="$(curl -sS -o /dev/null -w '%{http_code}' http://127.0.0.1/ycode/releases/latest.json || true)"
if [ -f '${SERVER_RELEASES_ROOT}/latest.json' ]; then
expected_status=200
else
expected_status=404
fi
if [ "$status" != "$expected_status" ]; then
echo "unexpected /ycode/releases/latest.json status: $status (expected $expected_status)" >&2
exit 1
fi
page_status="$(curl -sS -o /dev/null -w '%{http_code}' http://127.0.0.1/ycode/releases/ || true)"
if [ "$page_status" != "200" ]; then
echo "unexpected /ycode/releases/ status: $page_status (expected 200)" >&2
exit 1
fi
printf 'site=%s\\n' "$site"
printf 'backup=%s\\n' "$config_backup"
printf 'snippet=%s\\n' "$snippet"
printf 'latest_status=%s\\n' "$status"
printf 'page_status=%s\\n' "$page_status"
`
const output = runSsh(host, script)
process.stdout.write(output)
console.log(`Provisioned ${host}; no release manifest was created.`)
}
main().catch((error) => usageError(usage, error))