mirror of
https://github.com/larksuite/cli.git
synced 2026-07-10 11:04:26 +08:00
docs: add canonical svglide ppe setup
This commit is contained in:
258
scripts/dev-svglide-ppe-env.sh
Executable file
258
scripts/dev-svglide-ppe-env.sh
Executable file
@@ -0,0 +1,258 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
RULE_GROUP="lark-cli"
|
||||
CANONICAL_RULE_NAME="lark-cli-openapi-ppe-svg-slides"
|
||||
PROXY_HOST="${LARK_CLI_PROXY_HOST:-127.0.0.1}"
|
||||
PROXY_PORT="${LARK_CLI_PROXY_PORT:-8899}"
|
||||
|
||||
# Keep this list intentionally small and explicit. These were previous local
|
||||
# SVGlide/PPE rule names that can route generated SVG Slides to the wrong lane.
|
||||
# Do not store them in a whitespace-split variable: this script is meant to be
|
||||
# sourced by zsh as well as POSIX shells, and zsh does not split scalars by
|
||||
# whitespace unless SH_WORD_SPLIT is enabled.
|
||||
|
||||
fail() {
|
||||
printf '%s\n' "[svglide-ppe] $*" >&2
|
||||
return 1 2>/dev/null || exit 1
|
||||
}
|
||||
|
||||
info() {
|
||||
printf '%s\n' "[svglide-ppe] $*" >&2
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
Usage:
|
||||
. ./scripts/dev-svglide-ppe-env.sh pre [--host <host>] [--port <port>] [--no-clear]
|
||||
. ./scripts/dev-svglide-ppe-env.sh off
|
||||
./scripts/dev-svglide-ppe-env.sh rules
|
||||
|
||||
Notes:
|
||||
- Use "source" or "." for pre/off so proxy env vars apply to the current shell.
|
||||
- pre writes the canonical Whistle rule "${CANONICAL_RULE_NAME}".
|
||||
- pre also clears known legacy SVGlide/PPE rule names unless --no-clear is passed.
|
||||
- This is dev-only PPE plumbing, not production publish behavior.
|
||||
USAGE
|
||||
}
|
||||
|
||||
is_sourced() {
|
||||
if [ -n "${BASH_VERSION-}" ]; then
|
||||
[ "${BASH_SOURCE[0]}" != "$0" ]
|
||||
return
|
||||
fi
|
||||
if [ -n "${ZSH_VERSION-}" ]; then
|
||||
case "${ZSH_EVAL_CONTEXT-}" in
|
||||
*:file:*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
pick_whistle_cmd() {
|
||||
if command -v w2 >/dev/null 2>&1; then
|
||||
printf '%s\n' "w2"
|
||||
return 0
|
||||
fi
|
||||
if command -v whistle >/dev/null 2>&1; then
|
||||
printf '%s\n' "whistle"
|
||||
return 0
|
||||
fi
|
||||
info "missing required command: w2 (or whistle)"
|
||||
info "install: npm install -g whistle"
|
||||
info "then: w2 start && w2 ca"
|
||||
fail "missing required command: w2 (or whistle)"
|
||||
}
|
||||
|
||||
ensure_whistle_running() {
|
||||
wcmd="$1"
|
||||
whistle_status="$("$wcmd" status 2>&1 || true)"
|
||||
case "$whistle_status" in
|
||||
*"No running Whistle instances"*)
|
||||
info "Whistle is not running, starting it now..."
|
||||
"$wcmd" start >/dev/null 2>&1 || fail "failed to start Whistle"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
canonical_rules() {
|
||||
cat <<'RULES'
|
||||
/^https:\/\/open\.feishu\.cn\/(.*)$/ https://open.feishu-pre.cn/$1
|
||||
https://open.feishu.cn/ reqHeaders://Env=Pre_release
|
||||
https://open.feishu.cn/ reqHeaders://x-tt-env=ppe_svg_slides
|
||||
https://open.feishu.cn/ reqHeaders://x-use-ppe=1
|
||||
https://open.feishu-pre.cn/ reqHeaders://Env=Pre_release
|
||||
https://open.feishu-pre.cn/ reqHeaders://x-tt-env=ppe_svg_slides
|
||||
https://open.feishu-pre.cn/ reqHeaders://x-use-ppe=1
|
||||
/^https:\/\/accounts\.feishu\.cn\/(.*)$/ https://accounts.feishu-pre.cn/$1
|
||||
RULES
|
||||
}
|
||||
|
||||
disabled_rules() {
|
||||
rule_name="$1"
|
||||
cat <<RULES
|
||||
# disabled by scripts/dev-svglide-ppe-env.sh
|
||||
# canonical SVGlide PPE rule: ${CANONICAL_RULE_NAME}
|
||||
# cleared legacy rule: ${rule_name}
|
||||
RULES
|
||||
}
|
||||
|
||||
write_rule_js() {
|
||||
output="$1"
|
||||
rule_name="$2"
|
||||
rules="$3"
|
||||
|
||||
RULE_NAME="$rule_name" RULE_GROUP="$RULE_GROUP" RULES="$rules" node >"$output" <<'NODE'
|
||||
const rule = {
|
||||
name: process.env.RULE_NAME,
|
||||
groupName: process.env.RULE_GROUP,
|
||||
rules: process.env.RULES || "",
|
||||
};
|
||||
process.stdout.write(`module.exports = function (callback) {
|
||||
callback(${JSON.stringify(rule, null, 2)});
|
||||
};
|
||||
`);
|
||||
NODE
|
||||
}
|
||||
|
||||
apply_rule() {
|
||||
wcmd="$1"
|
||||
rule_name="$2"
|
||||
rules="$3"
|
||||
|
||||
tmp_js="$(mktemp "${TMPDIR:-/tmp}/svglide-ppe-rule.XXXXXX.js")" || fail "failed to create temp file"
|
||||
write_rule_js "$tmp_js" "$rule_name" "$rules"
|
||||
"$wcmd" add "$tmp_js" --force >/dev/null 2>&1 || {
|
||||
rm -f "$tmp_js"
|
||||
fail "failed to apply Whistle rule: ${rule_name}"
|
||||
}
|
||||
rm -f "$tmp_js"
|
||||
}
|
||||
|
||||
clear_legacy_rules() {
|
||||
wcmd="$1"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-openapi-env-switch"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-openapi-ppe-svglide"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-openapi-ppe-pure-svg"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-openapi-ppe-pure-svg-control"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-openapi-ppe-svg-slides-header-only"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-pre-ppe-svglide-combined"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-ppe-pure-svg"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-ppe-svglide"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-prod-host-pre-env-ppe-header"
|
||||
clear_legacy_rule "$wcmd" "lark-cli-prod-ppe-svglide-header-only"
|
||||
}
|
||||
|
||||
clear_legacy_rule() {
|
||||
wcmd="$1"
|
||||
rule_name="$2"
|
||||
[ "$rule_name" = "$CANONICAL_RULE_NAME" ] && return 0
|
||||
remove_rule "$wcmd" "$rule_name" || apply_rule "$wcmd" "$rule_name" "$(disabled_rules "$rule_name")"
|
||||
info "cleared legacy Whistle rule: ${rule_name}"
|
||||
}
|
||||
|
||||
remove_rule() {
|
||||
_wcmd="$1"
|
||||
rule_name="$2"
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
return 1
|
||||
fi
|
||||
curl -fsS \
|
||||
-X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data "{\"name\":\"${rule_name}\"}" \
|
||||
"http://${PROXY_HOST}:${PROXY_PORT}/cgi-bin/rules/remove" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
apply_proxy_env() {
|
||||
proxy_url="http://${PROXY_HOST}:${PROXY_PORT}"
|
||||
export HTTPS_PROXY="$proxy_url"
|
||||
export https_proxy="$proxy_url"
|
||||
export HTTP_PROXY="$proxy_url"
|
||||
export http_proxy="$proxy_url"
|
||||
export ALL_PROXY="$proxy_url"
|
||||
export all_proxy="$proxy_url"
|
||||
unset LARK_CLI_NO_PROXY
|
||||
info "proxy env enabled: ${proxy_url}"
|
||||
}
|
||||
|
||||
clear_proxy_env() {
|
||||
unset HTTPS_PROXY https_proxy HTTP_PROXY http_proxy ALL_PROXY all_proxy
|
||||
unset LARK_CLI_NO_PROXY
|
||||
info "proxy env cleared"
|
||||
}
|
||||
|
||||
mode="${1:-}"
|
||||
[ "$mode" = "" ] && {
|
||||
usage
|
||||
return 0 2>/dev/null || exit 0
|
||||
}
|
||||
shift || true
|
||||
|
||||
clear_legacy="1"
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--host)
|
||||
[ "$#" -ge 2 ] || fail "--host requires a value"
|
||||
PROXY_HOST="$2"
|
||||
shift 2
|
||||
;;
|
||||
--port)
|
||||
[ "$#" -ge 2 ] || fail "--port requires a value"
|
||||
PROXY_PORT="$2"
|
||||
shift 2
|
||||
;;
|
||||
--no-clear)
|
||||
clear_legacy="0"
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
return 0 2>/dev/null || exit 0
|
||||
;;
|
||||
*)
|
||||
fail "unknown arg: $1"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$mode" in
|
||||
rules)
|
||||
canonical_rules
|
||||
;;
|
||||
pre)
|
||||
wcmd="$(pick_whistle_cmd)"
|
||||
ensure_whistle_running "$wcmd"
|
||||
if [ "$clear_legacy" = "1" ]; then
|
||||
clear_legacy_rules "$wcmd"
|
||||
fi
|
||||
apply_rule "$wcmd" "$CANONICAL_RULE_NAME" "$(canonical_rules)"
|
||||
info "applied canonical Whistle rule: ${CANONICAL_RULE_NAME}"
|
||||
if is_sourced; then
|
||||
apply_proxy_env
|
||||
else
|
||||
info "Whistle rule updated, but current shell env is unchanged."
|
||||
info "run with source: . ./scripts/dev-svglide-ppe-env.sh pre"
|
||||
fi
|
||||
info "active PPE lane: ppe_svg_slides"
|
||||
;;
|
||||
off|cancel)
|
||||
wcmd="$(pick_whistle_cmd)"
|
||||
ensure_whistle_running "$wcmd"
|
||||
clear_legacy_rules "$wcmd"
|
||||
apply_rule "$wcmd" "$CANONICAL_RULE_NAME" "$(disabled_rules "$CANONICAL_RULE_NAME")"
|
||||
info "disabled canonical Whistle rule: ${CANONICAL_RULE_NAME}"
|
||||
if is_sourced; then
|
||||
clear_proxy_env
|
||||
else
|
||||
info "Whistle rules disabled, but current shell env is unchanged."
|
||||
info "run with source: . ./scripts/dev-svglide-ppe-env.sh off"
|
||||
fi
|
||||
;;
|
||||
-h|--help|help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
fail "invalid mode: ${mode}; expected pre|off|rules"
|
||||
;;
|
||||
esac
|
||||
@@ -16,7 +16,7 @@ metadata:
|
||||
|----------|----------|-----------------|
|
||||
| 新建 PPT | 先规划 `slide_plan.json`,再按复杂度选择一步或两步创建 | `planning-layer.md`、`visual-planning.md`、`asset-planning.md`、`slides +create` |
|
||||
| 本地生成或校验 SVG Slides / SVGlide 产物 | 先读 `references/svg-slides/README.md`,生成 local publish-ready bundle;已有 publish-ready manifest 时用 `slides +create-svglide` 发布 | `references/svg-slides/README.md`、`lark-slides-create-svglide.md`、`scripts/validate_svg_deck.mjs`、`scripts/svg_slides_bundle.mjs` |
|
||||
| 发布已有 SVGlide manifest | 只做发布:读取 manifest、校验 receipt/hash/root、本地图片上传并改写 href,然后逐页提交 raw SVG | `slides +create-svglide --manifest manifest.json --as user`、`lark-slides-create-svglide.md` |
|
||||
| 发布已有 SVGlide manifest | 只做发布:读取 manifest、校验 receipt/hash/root、本地图片上传并改写 href,然后逐页提交 raw SVG;需要 PPE 时只用 `scripts/dev-svglide-ppe-env.sh` 的 `ppe_svg_slides` 规则 | `slides +create-svglide --manifest manifest.json --as user`、`lark-slides-create-svglide.md` |
|
||||
| 已有 PPT 大幅改写 | 多页整页重建用 `+replace-pages`,单页局部编辑用 `+replace-slide` | `xml_presentations.get`、`lark-slides-replace-pages.md`、`lark-slides-edit-workflows.md` |
|
||||
| 编辑单个标题、文本块、图片或局部元素 | 优先块级替换/插入,不改页序 | `slides +replace-slide`、`lark-slides-replace-slide.md` |
|
||||
| 读取或分析已有 PPT | 解析 slides/wiki token,回读全文或单页 XML,保存 `xml_presentation_id`、`slide_id`、`revision_id` | `xml_presentations.get`、`xml_presentation.slide.get` |
|
||||
|
||||
@@ -21,7 +21,7 @@ Use it only after the SVG Slides local generation/validation layer has produced
|
||||
- SVG/SVGlide authoring.
|
||||
- Preview, visual QA, or repair loops.
|
||||
- Automatically running online readback; callers must run the readback gate after publish.
|
||||
- PPE routing or Whistle setup.
|
||||
- PPE routing or Whistle setup. For internal PPE validation, use the dev-only script below.
|
||||
- Remote image fetching, image generation, or FileMetaMap shaping.
|
||||
|
||||
Generated SVG decks must not bypass this command by calling `slides xml_presentation.slide create` directly. Direct raw API calls can prove transport only; they do not prove that the generated deck passed the SVGlide parser contract, bundle receipts, asset rewrite, or readback gates.
|
||||
@@ -32,6 +32,35 @@ Generated SVG decks must not bypass this command by calling `slides xml_presenta
|
||||
This limit is independent from `slides +create --slides`, whose inline JSON array is limited to 10 entries.
|
||||
Do not split a 12-page SVG Slides deck just because `+create --slides` has a 10-page inline payload limit.
|
||||
|
||||
## Internal PPE Lane
|
||||
|
||||
For internal online validation of SVG Slides, the only supported dev lane is `ppe_svg_slides`.
|
||||
Do not use older local lanes such as `ppe_svglide` or `ppe_pure_svg`.
|
||||
|
||||
Set or clear the rule with the tracked dev-only script:
|
||||
|
||||
```bash
|
||||
# enable the canonical rule and clear known legacy SVGlide/PPE rules
|
||||
. ./scripts/dev-svglide-ppe-env.sh pre
|
||||
|
||||
# print the canonical Whistle rules without applying them
|
||||
./scripts/dev-svglide-ppe-env.sh rules
|
||||
|
||||
# disable the canonical rule and clear known legacy rules
|
||||
. ./scripts/dev-svglide-ppe-env.sh off
|
||||
```
|
||||
|
||||
The expected effective request route is:
|
||||
|
||||
```text
|
||||
host: open.feishu-pre.cn
|
||||
Env: Pre_release
|
||||
x-tt-env: ppe_svg_slides
|
||||
x-use-ppe: 1
|
||||
```
|
||||
|
||||
This script is not part of production publish behavior. It exists only to make local/PPE validation reproducible.
|
||||
|
||||
## Manifest
|
||||
|
||||
Minimum shape:
|
||||
|
||||
Reference in New Issue
Block a user