@clawos-dev/clawd 0.2.568 → 0.2.569

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.
@@ -24796,6 +24796,18 @@ var z2 = external_exports.object({ version: external_exports.literal(2), scans:
24796
24796
  // src/deploy/templates.ts
24797
24797
  var CLAWOS_REPO = "ottin4ttc/clawos";
24798
24798
  var CLAWOS_REF = "release";
24799
+ var ACR_REGISTRY = "registry.cn-hangzhou.aliyuncs.com";
24800
+ var ACR_VPC_REGISTRY = "registry-vpc.cn-hangzhou.aliyuncs.com";
24801
+ var ACR_NAMESPACE = "ttc-prod";
24802
+ var BASE_IMAGE = `${ACR_REGISTRY}/${ACR_NAMESPACE}/clawd-persona-base:release`;
24803
+ var DOCKERIGNORE_TEMPLATE = [
24804
+ "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF08\u540C Dockerfile\uFF09\u3002",
24805
+ ".git",
24806
+ ".github",
24807
+ "Dockerfile",
24808
+ ".dockerignore",
24809
+ ""
24810
+ ].join("\n");
24799
24811
  var PLAN_STEP = [
24800
24812
  " - name: \u8BFB\u90E8\u7F72\u6587\u4EF6",
24801
24813
  " id: plan",
@@ -24803,9 +24815,7 @@ var PLAN_STEP = [
24803
24815
  " node clawos/cloud-host/pipeline/deploy-file.mjs \\",
24804
24816
  " --persona-dir persona \\",
24805
24817
  " --repo-name '${{ github.event.repository.name }}' \\",
24806
- " --sha '${{ github.sha }}' \\",
24807
- ' --image-repo "$VPC_REGISTRY/$IMAGE_NAME" \\',
24808
- ' --assets clawos/cloud-host/provision/manifests/assets.json >> "$GITHUB_OUTPUT"',
24818
+ ` --sha '\${{ github.sha }}' >> "$GITHUB_OUTPUT"`,
24809
24819
  ""
24810
24820
  ];
24811
24821
  var CONTRACT_STEPS = [
@@ -24815,7 +24825,7 @@ var CONTRACT_STEPS = [
24815
24825
  " path: persona",
24816
24826
  " sparse-checkout: .clawd",
24817
24827
  "",
24818
- " - name: Checkout clawos\uFF08\u6D41\u6C34\u7EBF\u811A\u672C + \u5B83\u5F15\u7684 k8s \u540D\u5B57\u6E05\u6D17 / \u8D44\u4EA7\u6E05\u5355\uFF09",
24828
+ " - name: Checkout clawos\uFF08\u6D41\u6C34\u7EBF\u811A\u672C + \u5B83\u5F15\u7684 k8s \u540D\u5B57\u6E05\u6D17\uFF09",
24819
24829
  " uses: actions/checkout@v4",
24820
24830
  " with:",
24821
24831
  " repository: ${{ env.CLAWOS_REPO }}",
@@ -24825,19 +24835,31 @@ var CONTRACT_STEPS = [
24825
24835
  " sparse-checkout: |",
24826
24836
  " cloud-host/pipeline",
24827
24837
  " cloud-host/k8s",
24828
- " cloud-host/provision/manifests",
24829
24838
  "",
24830
24839
  ...PLAN_STEP
24831
24840
  ];
24841
+ var ACR_LOGIN_STEPS = [
24842
+ " - name: Login to ACR\uFF08\u89E3\u6790\u955C\u50CF digest \u8981 docker \u51ED\u636E\uFF09",
24843
+ " uses: aliyun/acr-login@v1",
24844
+ " with:",
24845
+ " login-server: ${{ env.REGISTRY }}",
24846
+ ' username: "${{ secrets.ALI_DOCKER_USERNAME }}"',
24847
+ ' password: "${{ secrets.ALI_DOCKER_PASSWORD }}"',
24848
+ ""
24849
+ ];
24850
+ var IMAGE_LATEST = '"$REGISTRY/$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}:latest"';
24851
+ var RESOLVE_LINE = ` IMAGE_REF=$(node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY")`;
24832
24852
  var L = [
24833
24853
  "name: clawd deploy",
24834
24854
  "",
24835
24855
  "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF1A\u6BCF\u6B21\u300C\u53D1\u5E03\u300D\u90FD\u4F1A\u7528\u5F53\u524D\u6A21\u677F\u91CD\u5199\u8FD9\u4EFD\u6587\u4EF6\u518D\u63D0\u4EA4\uFF0C\u624B\u6539\u4F1A\u88AB\u76D6\u6389\u3002",
24836
- "# \u4E09\u6BB5\uFF1Abuild \u6784 persona \u5C42\u955C\u50CF\u63A8 ACR \u2192 smoke \u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21 \u2192 deploy \u5728 gateway \u767B\u8BB0\u6210\u6B63\u5F0F\u3002",
24837
- "# \u6784\u5EFA\u5668 / \u6D41\u6C34\u7EBF\u811A\u672C / \u968F\u884C\u8D44\u4EA7\u5728 ottin4ttc/clawos \u4ED3\u5E93\u91CC\uFF0C\u8FD9\u91CC checkout \u4E00\u4EFD\u6765\u7528\u3002",
24856
+ "# \u4E09\u6BB5\uFF1Abuild \u8BA9 ACR \u4ECE\u8FD9\u4E2A\u4ED3\u5E93\u6784 persona \u955C\u50CF\uFF08Dockerfile \u4E5F\u662F clawd \u5199\u7684\uFF09\u2192 smoke \u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21 \u2192 deploy \u5728 gateway \u767B\u8BB0\u6210\u6B63\u5F0F\u3002",
24857
+ "# \u955C\u50CF\u4E0D\u5728 runner \u4E0A\u6784\u3001\u4E5F\u4E0D\u4ECE runner \u63A8\uFF1AACR \u4E2A\u4EBA\u7248\u4ED3\u5E93 ttc-prod/<persona_id> \u6302\u7740\u8FD9\u4E2A GitHub \u4ED3\u5E93\u5F53\u4EE3\u7801\u6E90\uFF08\u9996\u6B21\u53D1\u5E03\u65F6\u81EA\u5EFA\uFF09\uFF0C",
24858
+ "# build \u6BB5\u53EA\u662F\u300C\u89E6\u53D1 \u2192 \u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\u300D\uFF1Bsmoke / deploy \u5404\u81EA\u628A :latest \u89E3\u6790\u6210 digest \u518D\u7528\u3002\u6D41\u6C34\u7EBF\u811A\u672C\u5728 ottin4ttc/clawos \u4ED3\u5E93\u91CC\u3002",
24838
24859
  "#",
24839
- "# \u8981\u7684\u7EC4\u7EC7\u7EA7 Secrets\uFF1AALI_DOCKER_USERNAME / ALI_DOCKER_PASSWORD\uFF08\u63A8 ACR\uFF09\u3001CLAWOS_READ_TOKEN",
24840
- "#\uFF08\u8BFB clawos \u4ED3\u5E93\uFF09\u3001CLAWD_GATEWAY_ADMIN_KEY\uFF1B\u7EC4\u7EC7\u7EA7 Variable\uFF1ACLAWD_GATEWAY_URL\u3002",
24860
+ "# \u8981\u7684\u7EC4\u7EC7\u7EA7 Secrets\uFF1AALI_ACS_ACCESS_KEY_ID / ALI_ACS_ACCESS_KEY_SECRET\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09\u3001",
24861
+ "# ALI_DOCKER_USERNAME / ALI_DOCKER_PASSWORD\uFF08\u89E3\u6790\u955C\u50CF digest\uFF09\u3001CLAWOS_READ_TOKEN\uFF08\u8BFB clawos \u4ED3\u5E93\uFF09\u3001CLAWD_GATEWAY_ADMIN_KEY\uFF1B",
24862
+ "# \u7EC4\u7EC7\u7EA7 Variable\uFF1ACLAWD_GATEWAY_URL\u3002",
24841
24863
  "# \u4ED3\u5E93\u7EA7\u540C\u540D\u914D\u7F6E\u4F1A\u76D6\u8FC7\u7EC4\u7EC7\u7EA7\u2014\u2014\u67D0\u4E2A persona \u8981\u6307\u5230\u53E6\u4E00\u53F0 gateway\uFF0C\u5728\u81EA\u5DF1\u4ED3\u5E93\u91CC\u914D\u5373\u53EF\u3002",
24842
24864
  "",
24843
24865
  "on:",
@@ -24850,9 +24872,9 @@ var L = [
24850
24872
  " group: persona-cloud-${{ github.repository }}",
24851
24873
  "",
24852
24874
  "env:",
24853
- " REGISTRY: registry.cn-hangzhou.aliyuncs.com",
24854
- " VPC_REGISTRY: registry-vpc.cn-hangzhou.aliyuncs.com",
24855
- " IMAGE_NAME: ttc-prod/clawd-persona-cloud",
24875
+ ` REGISTRY: ${ACR_REGISTRY}`,
24876
+ ` VPC_REGISTRY: ${ACR_VPC_REGISTRY}`,
24877
+ ` ACR_NAMESPACE: ${ACR_NAMESPACE}`,
24856
24878
  ` CLAWOS_REPO: ${CLAWOS_REPO}`,
24857
24879
  ` CLAWOS_REF: ${CLAWOS_REF}`,
24858
24880
  "",
@@ -24865,93 +24887,60 @@ var L = [
24865
24887
  // 中文说明归 clawd 的上云页面,这里保持机器好认。
24866
24888
  " name: build",
24867
24889
  " runs-on: ubuntu-latest",
24868
- " timeout-minutes: 30",
24869
- // 没有 outputs:——smoke / deploy 段自己读契约(文件头)。build 段整仓 checkout:构建器要拷整个 persona 目录。
24890
+ // ACR 个人版的构建按账号串行:底座(8 分钟)/ api 在前面排着时要等它们先构完。
24891
+ " timeout-minutes: 40",
24892
+ // 没有 outputs:——smoke / deploy 段自己读契约、自己解析 digest(文件头)。
24870
24893
  " steps:",
24871
- " - name: Checkout persona",
24872
- " uses: actions/checkout@v4",
24873
- " with:",
24874
- " path: persona",
24875
- "",
24876
- " - name: Checkout clawos\uFF08\u6784\u5EFA\u5668 / \u6D41\u6C34\u7EBF\u811A\u672C / \u968F\u884C\u8D44\u4EA7\uFF09",
24877
- " uses: actions/checkout@v4",
24878
- " with:",
24879
- " repository: ${{ env.CLAWOS_REPO }}",
24880
- " ref: ${{ env.CLAWOS_REF }}",
24881
- " token: ${{ secrets.CLAWOS_READ_TOKEN }}",
24882
- " path: clawos",
24883
- "",
24884
- ...PLAN_STEP,
24894
+ ...CONTRACT_STEPS,
24885
24895
  " - name: \u51ED\u636E\u9F50\u4E0D\u9F50\uFF08\u7F3A\u54EA\u51E0\u4E2A\u540D\u5B57\u4E00\u6B21\u5217\u5168\uFF09",
24886
24896
  " env:",
24887
24897
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24888
24898
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24889
24899
  " run: node clawos/cloud-host/pipeline/check-secrets.mjs",
24890
24900
  "",
24891
- " - uses: pnpm/action-setup@v4",
24892
- " if: steps.plan.outputs.asset_builds != ''",
24893
- " with:",
24894
- " version: 10",
24895
- "",
24896
- " - uses: actions/setup-node@v4",
24897
- " if: steps.plan.outputs.asset_builds != ''",
24898
- " with:",
24899
- " node-version: 20",
24900
- " cache: pnpm",
24901
- " cache-dependency-path: clawos/clawd/pnpm-lock.yaml",
24902
- "",
24903
- " - name: \u6784\u968F\u884C\u8D44\u4EA7\uFF08\u6E05\u5355\u91CC\u70B9\u8FC7\u540D\u3001\u4E14\u662F\u4ED3\u5E93\u6784\u5EFA\u4EA7\u7269\u7684\u90A3\u4E9B\uFF09",
24904
- " # \u547D\u4EE4\u6765\u81EA assets.json\uFF0C\u5B83\u81EA\u5DF1\u5E26\u88C5\u4F9D\u8D56\u90A3\u4E00\u6B65\u3002< /dev/null\uFF1A\u522B\u8BA9\u67D0\u6761\u547D\u4EE4\u628A here-string \u91CC\u5269\u4E0B\u7684\u884C\u5F53 stdin \u5403\u6389",
24905
- " if: steps.plan.outputs.asset_builds != ''",
24906
- " working-directory: clawos",
24901
+ " - name: Dockerfile \u5728\u3001\u4E14\u62F7\u5230\u7684\u662F\u8FD9\u4E2A persona \u7684\u76EE\u5F55",
24902
+ " # Dockerfile \u7531 clawd \u53D1\u5E03\u65F6\u5199\uFF08\u540C\u8FD9\u4EFD workflow\uFF09\uFF0CACR \u6309\u5B83\u6784\u3002\u76EE\u5F55\u540D\u90A3\u4E00\u6BB5\u8981\u4E0E deploy-file \u7B97\u51FA\u7684 persona_id \u4E00\u81F4\uFF1A",
24903
+ " # \u4E24\u8FB9\u5404\u6709\u4E00\u4EFD\u540C\u6837\u7684\u540D\u5B57\u6E05\u6D17\uFF0C\u8FD9\u91CC\u662F\u5B83\u4EEC\u552F\u4E00\u7684\u4EA4\u6C47\u70B9\u3002",
24907
24904
  " run: |",
24908
- " set -e",
24909
- " while IFS= read -r cmd; do",
24910
- ' [ -n "$cmd" ] || continue',
24911
- ' echo "$ $cmd"',
24912
- ' bash -c "$cmd" < /dev/null',
24913
- " done <<< '${{ steps.plan.outputs.asset_builds }}'",
24914
- "",
24915
- " - name: Login to ACR",
24916
- " uses: aliyun/acr-login@v1",
24917
- " with:",
24918
- " login-server: ${{ env.REGISTRY }}",
24919
- ' username: "${{ secrets.ALI_DOCKER_USERNAME }}"',
24920
- ' password: "${{ secrets.ALI_DOCKER_PASSWORD }}"',
24905
+ " test -f persona/Dockerfile \\",
24906
+ ' || { echo "\u2717 \u4ED3\u5E93\u91CC\u6CA1\u6709 Dockerfile\uFF1A\u8FD9\u6B21\u63A8\u9001\u4E0D\u662F clawd \u53D1\u5E03\u7684\uFF08\u6216 clawd \u592A\u65E7\uFF09\uFF1B\u56DE clawd \u7684\u4E0A\u4E91\u9875\u9762\u91CD\u65B0\u53D1\u5E03" >&2; exit 1; }',
24907
+ " grep -qF '/clawd/personas/${{ steps.plan.outputs.persona_id }}/' persona/Dockerfile \\",
24908
+ ' || { echo "\u2717 Dockerfile \u62F7\u5230\u7684\u76EE\u5F55\u4E0D\u662F /clawd/personas/${{ steps.plan.outputs.persona_id }}/" >&2; exit 1; }',
24921
24909
  "",
24922
- " - name: \u6784 persona \u5C42",
24923
- " # \u6784\u5EFA\u5668\u6574\u76EE\u5F55\u62F7\uFF0C`.git` \u4E0D\u662F\u4EBA\u683C\uFF0C\u5148\u5220\u3002\u5E95\u5EA7\u7528 :base \u79FB\u52A8 tag\u2014\u2014runner \u6BCF\u6B21\u90FD\u662F\u5E72\u51C0\u673A\u5668\u3001",
24924
- " # \u5FC5\u7136\u62C9\u6700\u65B0\uFF1Bpersona \u5C42\u81EA\u5DF1\u7684 tag \u5E26 commit sha\u3001\u4E0D\u53EF\u53D8\uFF0C\u96C6\u7FA4\u6309\u5B83\u62C9\u6CA1\u6709\u6B67\u4E49\u3002",
24910
+ " - name: \u88C5 aliyun CLI\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09",
24911
+ " env:",
24912
+ " GH_TOKEN: ${{ github.token }}",
24925
24913
  " run: |",
24926
- " rm -rf persona/.git",
24927
- " node clawos/cloud-host/provision/build-image.mjs \\",
24928
- " --manifest persona/.clawd/deploy.json \\",
24929
- ' --from "$REGISTRY/$IMAGE_NAME:base-${{ steps.plan.outputs.engine }}" \\',
24930
- " --persona-dir persona \\",
24931
- // persona 在镜像里落 /clawd/personas/<id>/(与本机同构),id 是 gateway 登记的名字;同 smoke / register 用的那个输出
24932
- " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
24933
- ' --tag "$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
24914
+ " TAGNAME=$(gh release view --repo aliyun/aliyun-cli --json tagName -q .tagName)",
24915
+ // 不用 ${TAGNAME#v} 这种带花括号的展开:这份模板里 `${` 只许出现在 GitHub 表达式里(spec 守着)
24916
+ ' VER=$(printf %s "$TAGNAME" | sed s/^v//)',
24917
+ ' curl -fsSL -o /tmp/aliyun-cli.tgz "https://github.com/aliyun/aliyun-cli/releases/download/$TAGNAME/aliyun-cli-linux-$VER-amd64.tgz"',
24918
+ " sudo tar -xzf /tmp/aliyun-cli.tgz -C /usr/local/bin",
24919
+ " aliyun version",
24934
24920
  "",
24935
- " - name: \u955C\u50CF\u65AD\u8A00\uFF08\u6E05\u5355\u91CC\u8981\u88C5\u7684\u90FD\u5728\u3001bundle \u91CC persona \u5728\uFF09",
24936
- " # /opt/versions.sh \u6BCF\u884C\u90FD\u4EE5 `|| echo` \u6536\u5C3E\u3001\u6C38\u8FDC exit 0\uFF0C\u53EA\u80FD\u9A8C\u8F93\u51FA\uFF1A\u6BB5\u6570\u8981\u7B49\u4E8E\u6E05\u5355 packages \u7684",
24937
- " # \u6761\u6570\uFF0C\u6BCF\u6BB5\u4E0B\u9762\u8981\u6709\u7248\u672C\u53F7\u3002\u955C\u50CF ENTRYPOINT \u662F sh -c\uFF0C\u547D\u4EE4\u8981\u4F5C\u4E3A\u4E00\u4E2A\u5B57\u7B26\u4E32\u4F20\u3002",
24921
+ " - name: \u8BA9 ACR \u4ECE\u672C\u4ED3\u5E93\u6784\uFF08\u9996\u6B21\u53D1\u5E03\u5148\u5EFA ACR \u4ED3\u5E93\u4E0E\u89C4\u5219\uFF1B\u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\uFF09",
24922
+ " # ACR \u6784\u7684\u662F main \u5F53\u524D\u7684 tip\u3001\u4E0D\u662F github.sha\uFF1Atip \u5DF2\u7ECF\u4E0D\u662F\u672C\u6B21 commit \u65F6\u76F4\u63A5\u7EA2\uFF0C\u8BA9\u66F4\u65B0\u7684\u90A3\u6B21 run \u53BB\u6784\u3001\u53BB\u767B\u8BB0\u3002",
24923
+ " # \u81EA\u52A8\u6784\u5EFA\u5173\u7740\uFF1A\u53EA\u6709\u8FD9\u91CC\u89E6\u53D1\u3001webhook \u4E0D\u6784\uFF0C\u300C\u6784 \u2192 \u5192\u70DF \u2192 \u767B\u8BB0\u300D\u624D\u662F\u4E00\u6761\u6709\u5E8F\u7684\u94FE\u3002",
24924
+ " # \u6784\u51FA\u7684\u662F\u54EA\u4E2A commit \u7531 acr.mjs wait \u6309\u6784\u5EFA\u8BB0\u5F55 + \u65E5\u5FD7\u91CC\u7684 commit \u6838\uFF0C\u4E0D\u770B\u955C\u50CF\u7684\u65F6\u95F4\uFF08\u7F13\u5B58\u547D\u4E2D\u65F6\u90A3\u662F\u8001\u7684\uFF09\u3002",
24925
+ " env:",
24926
+ " ALIBABA_CLOUD_ACCESS_KEY_ID: ${{ secrets.ALI_ACS_ACCESS_KEY_ID }}",
24927
+ " ALIBABA_CLOUD_ACCESS_KEY_SECRET: ${{ secrets.ALI_ACS_ACCESS_KEY_SECRET }}",
24938
24928
  " run: |",
24939
- ' IMG="$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
24940
- ` OUT=$(docker run --rm "$IMG" '/opt/versions.sh')`,
24941
- ' echo "$OUT"',
24942
- ` WANT=$(node -e 'const m=JSON.parse(require("fs").readFileSync("persona/.clawd/deploy.json","utf8"));const b=m.manifest??m;console.log((b.packages??b.clis??[]).length)')`,
24943
- ` echo "$OUT" | awk -v want="$WANT" '`,
24944
- ' /^--- / { name=$2; if ((getline v) <= 0) v=""; n++',
24945
- ' if (v !~ /[0-9]+\\.[0-9]+/) { printf " \u2717 %s \u6CA1\u62A5\u51FA\u7248\u672C\u53F7\uFF1A%s\\n", name, v > "/dev/stderr"; bad++ } }',
24946
- ' END { if (n != want) { printf " \u2717 \u955C\u50CF\u91CC\u53EA\u6709 %d \u6BB5\u7248\u672C\u8F93\u51FA\uFF0C\u6E05\u5355\u8981\u88C5 %d \u4E2A\\n", n, want > "/dev/stderr"; bad++ }',
24947
- " exit bad ? 1 : 0 }'",
24948
- ' echo " \u2713 \u6E05\u5355\u91CC\u8981\u88C5\u7684 $WANT \u4E2A\u90FD\u5728\u4E14\u62A5\u5F97\u51FA\u7248\u672C"',
24949
- ` docker run --rm "$IMG" 'test -d /clawd/personas/\${{ steps.plan.outputs.persona_id }}' \\`,
24950
- ' || { echo " \u2717 /clawd/personas/${{ steps.plan.outputs.persona_id }} \u4E0D\u5728" >&2; exit 1; }',
24951
- ' echo " \u2713 persona \u76EE\u5F55\u5728"',
24929
+ // pipefail:ls-remote 那条管道里 cut 永远退 0,没有 pipefail 的话 ls-remote 挂了 TIP 是空串、红在「main 已经推进到 」这句误导人的话上
24930
+ " set -eo pipefail",
24931
+ ' REPO="$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}"',
24932
+ ' node clawos/cloud-host/pipeline/acr.mjs ensure-repo --repo "$REPO" \\',
24933
+ " --source '${{ github.repository }}' --location / --dockerfile Dockerfile --branch main --tag latest \\",
24934
+ " --summary 'clawd persona ${{ github.event.repository.name }}'",
24935
+ " TIP=$(git -C persona ls-remote origin refs/heads/main | cut -f1)",
24936
+ ` [ "$TIP" = '\${{ github.sha }}' ] \\`,
24937
+ ' || { echo "\u2717 main \u5DF2\u7ECF\u63A8\u8FDB\u5230 $TIP\uFF0C\u672C\u6B21 ${{ github.sha }} \u4E0D\u518D\u6784\uFF1B\u7B49\u65B0\u7684\u90A3\u6B21 run" >&2; exit 1; }',
24938
+ ' node clawos/cloud-host/pipeline/acr.mjs trigger --repo "$REPO" --tag latest',
24939
+ ` node clawos/cloud-host/pipeline/acr.mjs wait --repo "$REPO" --tag latest --commit '\${{ github.sha }}' --timeout-sec 1800`,
24952
24940
  "",
24953
- " - name: Push to ACR",
24954
- ' run: docker push "$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
24941
+ ...ACR_LOGIN_STEPS,
24942
+ " - name: \u955C\u50CF = \u672C\u6B21 commit \u6784\u51FA\u7684\u90A3\u4EFD\uFF08digest\uFF1B\u53EA\u6253\u65E5\u5FD7\uFF0Csmoke / deploy \u5404\u81EA\u518D\u89E3\u6790\u4E00\u6B21\uFF09",
24943
+ ` run: node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY"`,
24955
24944
  "",
24956
24945
  " smoke:",
24957
24946
  " name: smoke",
@@ -24960,9 +24949,10 @@ var L = [
24960
24949
  " timeout-minutes: 20",
24961
24950
  " steps:",
24962
24951
  ...CONTRACT_STEPS,
24952
+ ...ACR_LOGIN_STEPS,
24963
24953
  " - name: \u4E34\u65F6\u767B\u8BB0 \u2192 \u8D77\u4E00\u6B21 Pod \u2192 \u64A4\u9500",
24964
24954
  " # \u767B\u8BB0\u6B63\u5F0F\u53EA\u662F\u5F80 gateway \u5199\u4E00\u884C\uFF0Cgateway \u4E0D\u78B0\u955C\u50CF\uFF1B\u96C6\u7FA4\u62C9\u955C\u50CF\u53D1\u751F\u5728\u7B2C\u4E00\u4E2A\u4EFB\u52A1\u5230\u6765\u65F6\u3002",
24965
- " # \u6CA1\u6709\u8FD9\u4E00\u6B65\uFF0C\u6D41\u6C34\u7EBF\u7EFF\u4E86\u53EA\u4EE3\u8868\u300C\u767B\u8BB0\u4E86\u300D\u3002",
24955
+ " # \u6CA1\u6709\u8FD9\u4E00\u6B65\uFF0C\u6D41\u6C34\u7EBF\u7EFF\u4E86\u53EA\u4EE3\u8868\u300C\u767B\u8BB0\u4E86\u300D\u3002\u955C\u50CF\u7528 digest\uFF08\u96C6\u7FA4 Job \u662F IfNotPresent\uFF0C\u79FB\u52A8 tag \u4F1A\u4E00\u76F4\u8DD1\u65E7\u7684\uFF09\u3002",
24966
24956
  // 模型 / 档位 / 连接器 smoke 也要:试跑那次要跟正式那次拿到同一份,否则验的不是将要上线的东西。
24967
24957
  // 名字形状 deploy-file.mjs 已卡死(persona_id [a-z0-9-]、model / effort [A-Za-z0-9._/-](`/` 是 pi 的 provider/id,不是元字符)、size 四档枚举、task_concurrency 正整数、connectors 无单引号
24968
24958
  // 无换行),所以单引号包住直接拼进命令行是安全的。
@@ -24972,8 +24962,10 @@ var L = [
24972
24962
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24973
24963
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24974
24964
  " run: |",
24965
+ " set -e",
24966
+ RESOLVE_LINE,
24975
24967
  " node clawos/cloud-host/pipeline/smoke.mjs \\",
24976
- " --image '${{ steps.plan.outputs.image }}' \\",
24968
+ ' --image "$IMAGE_REF" \\',
24977
24969
  " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
24978
24970
  " --model '${{ steps.plan.outputs.model }}' \\",
24979
24971
  " --effort '${{ steps.plan.outputs.effort }}' \\",
@@ -24991,6 +24983,7 @@ var L = [
24991
24983
  " environment: production",
24992
24984
  " steps:",
24993
24985
  ...CONTRACT_STEPS,
24986
+ ...ACR_LOGIN_STEPS,
24994
24987
  " - name: \u767B\u8BB0\u6B63\u5F0F",
24995
24988
  " env:",
24996
24989
  " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_GATEWAY_URL }}",
@@ -24998,8 +24991,10 @@ var L = [
24998
24991
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24999
24992
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
25000
24993
  " run: |",
24994
+ " set -e",
24995
+ RESOLVE_LINE,
25001
24996
  " node clawos/cloud-host/pipeline/register.mjs \\",
25002
- " --image '${{ steps.plan.outputs.image }}' \\",
24997
+ ' --image "$IMAGE_REF" \\',
25003
24998
  " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
25004
24999
  " --model '${{ steps.plan.outputs.model }}' \\",
25005
25000
  " --effort '${{ steps.plan.outputs.effort }}' \\",
package/dist/cli.cjs CHANGED
@@ -59286,6 +59286,14 @@ init_protocol();
59286
59286
  var CLAWOS_REPO = "ottin4ttc/clawos";
59287
59287
  var CLAWOS_REF = "release";
59288
59288
  var WORKFLOW_PATH = ".github/workflows/clawd-deploy.yml";
59289
+ var DOCKERFILE_PATH = "Dockerfile";
59290
+ var DOCKERIGNORE_PATH = ".dockerignore";
59291
+ var ACR_REGISTRY = "registry.cn-hangzhou.aliyuncs.com";
59292
+ var ACR_VPC_REGISTRY = "registry-vpc.cn-hangzhou.aliyuncs.com";
59293
+ var ACR_NAMESPACE = "ttc-prod";
59294
+ var BASE_IMAGE = `${ACR_REGISTRY}/${ACR_NAMESPACE}/clawd-persona-base:release`;
59295
+ var PERSONA_LAYER_SCRIPT = "/opt/persona-layer.mjs";
59296
+ var CLOUD_PERSONAS_ROOT = "/clawd/personas";
59289
59297
  var GITIGNORE_LINES = [
59290
59298
  "projects/",
59291
59299
  ".attachments/",
@@ -59304,6 +59312,32 @@ function mergeGitignore(existing) {
59304
59312
  return `${base}${missing.join("\n")}
59305
59313
  `;
59306
59314
  }
59315
+ function personaIdOf(repoName) {
59316
+ return String(repoName).toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
59317
+ }
59318
+ function renderDockerfile(personaId2) {
59319
+ if (!/^[a-z0-9][a-z0-9-]{0,39}$/.test(personaId2)) throw new Error(`persona id \u4E0D\u5408\u5F62\u72B6\uFF08[a-z0-9-]\uFF0C\u226440\uFF09\uFF1A${JSON.stringify(personaId2)}`);
59320
+ const dir = `${CLOUD_PERSONAS_ROOT}/${personaId2}`;
59321
+ return [
59322
+ "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF1A\u6BCF\u6B21\u300C\u53D1\u5E03\u300D\u90FD\u4F1A\u7528\u5F53\u524D\u6A21\u677F\u91CD\u5199\u8FD9\u4EFD\u6587\u4EF6\u518D\u63D0\u4EA4\uFF0C\u624B\u6539\u4F1A\u88AB\u76D6\u6389\u3002",
59323
+ "# \u963F\u91CC\u4E91\u5BB9\u5668\u955C\u50CF\u670D\u52A1\uFF08ACR\uFF09\u4ECE\u8FD9\u4E2A\u4ED3\u5E93\u6784 persona \u955C\u50CF\u65F6\u7528\u5B83\uFF1BGitHub \u7684 runner \u4E0D\u6784\u3001\u4E0D\u63A8\u955C\u50CF\u3002",
59324
+ "# \u8981\u88C5\u4EC0\u4E48\u5199\u5728 .clawd/deploy.json \u91CC\uFF0C\u7531\u5E95\u5EA7\u81EA\u5E26\u7684\u5B89\u88C5\u5668\u5728\u6784\u5EFA\u65F6\u73B0\u88C5\u2014\u2014\u8FD9\u91CC\u4E0D\u5217\u4EFB\u4F55\u4E00\u6761\u4F9D\u8D56\uFF0C",
59325
+ "# \u6240\u4EE5\u6587\u4EF6\u4E0D\u968F\u6E05\u5355\u53D8\uFF1B\u5148\u53EA\u62F7\u6E05\u5355\u518D\u88C5\uFF0Cpersona \u5185\u5BB9\u6539\u4E86\u4E5F\u4E0D\u7528\u91CD\u88C5\u3002",
59326
+ `FROM ${BASE_IMAGE}`,
59327
+ `COPY .clawd/deploy.json ${dir}/.clawd/deploy.json`,
59328
+ `RUN node ${PERSONA_LAYER_SCRIPT} ${dir}`,
59329
+ `COPY . ${dir}/`,
59330
+ ""
59331
+ ].join("\n");
59332
+ }
59333
+ var DOCKERIGNORE_TEMPLATE = [
59334
+ "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF08\u540C Dockerfile\uFF09\u3002",
59335
+ ".git",
59336
+ ".github",
59337
+ "Dockerfile",
59338
+ ".dockerignore",
59339
+ ""
59340
+ ].join("\n");
59307
59341
  var PLAN_STEP = [
59308
59342
  " - name: \u8BFB\u90E8\u7F72\u6587\u4EF6",
59309
59343
  " id: plan",
@@ -59311,9 +59345,7 @@ var PLAN_STEP = [
59311
59345
  " node clawos/cloud-host/pipeline/deploy-file.mjs \\",
59312
59346
  " --persona-dir persona \\",
59313
59347
  " --repo-name '${{ github.event.repository.name }}' \\",
59314
- " --sha '${{ github.sha }}' \\",
59315
- ' --image-repo "$VPC_REGISTRY/$IMAGE_NAME" \\',
59316
- ' --assets clawos/cloud-host/provision/manifests/assets.json >> "$GITHUB_OUTPUT"',
59348
+ ` --sha '\${{ github.sha }}' >> "$GITHUB_OUTPUT"`,
59317
59349
  ""
59318
59350
  ];
59319
59351
  var CONTRACT_STEPS = [
@@ -59323,7 +59355,7 @@ var CONTRACT_STEPS = [
59323
59355
  " path: persona",
59324
59356
  " sparse-checkout: .clawd",
59325
59357
  "",
59326
- " - name: Checkout clawos\uFF08\u6D41\u6C34\u7EBF\u811A\u672C + \u5B83\u5F15\u7684 k8s \u540D\u5B57\u6E05\u6D17 / \u8D44\u4EA7\u6E05\u5355\uFF09",
59358
+ " - name: Checkout clawos\uFF08\u6D41\u6C34\u7EBF\u811A\u672C + \u5B83\u5F15\u7684 k8s \u540D\u5B57\u6E05\u6D17\uFF09",
59327
59359
  " uses: actions/checkout@v4",
59328
59360
  " with:",
59329
59361
  " repository: ${{ env.CLAWOS_REPO }}",
@@ -59333,19 +59365,31 @@ var CONTRACT_STEPS = [
59333
59365
  " sparse-checkout: |",
59334
59366
  " cloud-host/pipeline",
59335
59367
  " cloud-host/k8s",
59336
- " cloud-host/provision/manifests",
59337
59368
  "",
59338
59369
  ...PLAN_STEP
59339
59370
  ];
59371
+ var ACR_LOGIN_STEPS = [
59372
+ " - name: Login to ACR\uFF08\u89E3\u6790\u955C\u50CF digest \u8981 docker \u51ED\u636E\uFF09",
59373
+ " uses: aliyun/acr-login@v1",
59374
+ " with:",
59375
+ " login-server: ${{ env.REGISTRY }}",
59376
+ ' username: "${{ secrets.ALI_DOCKER_USERNAME }}"',
59377
+ ' password: "${{ secrets.ALI_DOCKER_PASSWORD }}"',
59378
+ ""
59379
+ ];
59380
+ var IMAGE_LATEST = '"$REGISTRY/$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}:latest"';
59381
+ var RESOLVE_LINE = ` IMAGE_REF=$(node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY")`;
59340
59382
  var L2 = [
59341
59383
  "name: clawd deploy",
59342
59384
  "",
59343
59385
  "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF1A\u6BCF\u6B21\u300C\u53D1\u5E03\u300D\u90FD\u4F1A\u7528\u5F53\u524D\u6A21\u677F\u91CD\u5199\u8FD9\u4EFD\u6587\u4EF6\u518D\u63D0\u4EA4\uFF0C\u624B\u6539\u4F1A\u88AB\u76D6\u6389\u3002",
59344
- "# \u4E09\u6BB5\uFF1Abuild \u6784 persona \u5C42\u955C\u50CF\u63A8 ACR \u2192 smoke \u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21 \u2192 deploy \u5728 gateway \u767B\u8BB0\u6210\u6B63\u5F0F\u3002",
59345
- "# \u6784\u5EFA\u5668 / \u6D41\u6C34\u7EBF\u811A\u672C / \u968F\u884C\u8D44\u4EA7\u5728 ottin4ttc/clawos \u4ED3\u5E93\u91CC\uFF0C\u8FD9\u91CC checkout \u4E00\u4EFD\u6765\u7528\u3002",
59386
+ "# \u4E09\u6BB5\uFF1Abuild \u8BA9 ACR \u4ECE\u8FD9\u4E2A\u4ED3\u5E93\u6784 persona \u955C\u50CF\uFF08Dockerfile \u4E5F\u662F clawd \u5199\u7684\uFF09\u2192 smoke \u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21 \u2192 deploy \u5728 gateway \u767B\u8BB0\u6210\u6B63\u5F0F\u3002",
59387
+ "# \u955C\u50CF\u4E0D\u5728 runner \u4E0A\u6784\u3001\u4E5F\u4E0D\u4ECE runner \u63A8\uFF1AACR \u4E2A\u4EBA\u7248\u4ED3\u5E93 ttc-prod/<persona_id> \u6302\u7740\u8FD9\u4E2A GitHub \u4ED3\u5E93\u5F53\u4EE3\u7801\u6E90\uFF08\u9996\u6B21\u53D1\u5E03\u65F6\u81EA\u5EFA\uFF09\uFF0C",
59388
+ "# build \u6BB5\u53EA\u662F\u300C\u89E6\u53D1 \u2192 \u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\u300D\uFF1Bsmoke / deploy \u5404\u81EA\u628A :latest \u89E3\u6790\u6210 digest \u518D\u7528\u3002\u6D41\u6C34\u7EBF\u811A\u672C\u5728 ottin4ttc/clawos \u4ED3\u5E93\u91CC\u3002",
59346
59389
  "#",
59347
- "# \u8981\u7684\u7EC4\u7EC7\u7EA7 Secrets\uFF1AALI_DOCKER_USERNAME / ALI_DOCKER_PASSWORD\uFF08\u63A8 ACR\uFF09\u3001CLAWOS_READ_TOKEN",
59348
- "#\uFF08\u8BFB clawos \u4ED3\u5E93\uFF09\u3001CLAWD_GATEWAY_ADMIN_KEY\uFF1B\u7EC4\u7EC7\u7EA7 Variable\uFF1ACLAWD_GATEWAY_URL\u3002",
59390
+ "# \u8981\u7684\u7EC4\u7EC7\u7EA7 Secrets\uFF1AALI_ACS_ACCESS_KEY_ID / ALI_ACS_ACCESS_KEY_SECRET\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09\u3001",
59391
+ "# ALI_DOCKER_USERNAME / ALI_DOCKER_PASSWORD\uFF08\u89E3\u6790\u955C\u50CF digest\uFF09\u3001CLAWOS_READ_TOKEN\uFF08\u8BFB clawos \u4ED3\u5E93\uFF09\u3001CLAWD_GATEWAY_ADMIN_KEY\uFF1B",
59392
+ "# \u7EC4\u7EC7\u7EA7 Variable\uFF1ACLAWD_GATEWAY_URL\u3002",
59349
59393
  "# \u4ED3\u5E93\u7EA7\u540C\u540D\u914D\u7F6E\u4F1A\u76D6\u8FC7\u7EC4\u7EC7\u7EA7\u2014\u2014\u67D0\u4E2A persona \u8981\u6307\u5230\u53E6\u4E00\u53F0 gateway\uFF0C\u5728\u81EA\u5DF1\u4ED3\u5E93\u91CC\u914D\u5373\u53EF\u3002",
59350
59394
  "",
59351
59395
  "on:",
@@ -59358,9 +59402,9 @@ var L2 = [
59358
59402
  " group: persona-cloud-${{ github.repository }}",
59359
59403
  "",
59360
59404
  "env:",
59361
- " REGISTRY: registry.cn-hangzhou.aliyuncs.com",
59362
- " VPC_REGISTRY: registry-vpc.cn-hangzhou.aliyuncs.com",
59363
- " IMAGE_NAME: ttc-prod/clawd-persona-cloud",
59405
+ ` REGISTRY: ${ACR_REGISTRY}`,
59406
+ ` VPC_REGISTRY: ${ACR_VPC_REGISTRY}`,
59407
+ ` ACR_NAMESPACE: ${ACR_NAMESPACE}`,
59364
59408
  ` CLAWOS_REPO: ${CLAWOS_REPO}`,
59365
59409
  ` CLAWOS_REF: ${CLAWOS_REF}`,
59366
59410
  "",
@@ -59373,93 +59417,60 @@ var L2 = [
59373
59417
  // 中文说明归 clawd 的上云页面,这里保持机器好认。
59374
59418
  " name: build",
59375
59419
  " runs-on: ubuntu-latest",
59376
- " timeout-minutes: 30",
59377
- // 没有 outputs:——smoke / deploy 段自己读契约(文件头)。build 段整仓 checkout:构建器要拷整个 persona 目录。
59420
+ // ACR 个人版的构建按账号串行:底座(8 分钟)/ api 在前面排着时要等它们先构完。
59421
+ " timeout-minutes: 40",
59422
+ // 没有 outputs:——smoke / deploy 段自己读契约、自己解析 digest(文件头)。
59378
59423
  " steps:",
59379
- " - name: Checkout persona",
59380
- " uses: actions/checkout@v4",
59381
- " with:",
59382
- " path: persona",
59383
- "",
59384
- " - name: Checkout clawos\uFF08\u6784\u5EFA\u5668 / \u6D41\u6C34\u7EBF\u811A\u672C / \u968F\u884C\u8D44\u4EA7\uFF09",
59385
- " uses: actions/checkout@v4",
59386
- " with:",
59387
- " repository: ${{ env.CLAWOS_REPO }}",
59388
- " ref: ${{ env.CLAWOS_REF }}",
59389
- " token: ${{ secrets.CLAWOS_READ_TOKEN }}",
59390
- " path: clawos",
59391
- "",
59392
- ...PLAN_STEP,
59424
+ ...CONTRACT_STEPS,
59393
59425
  " - name: \u51ED\u636E\u9F50\u4E0D\u9F50\uFF08\u7F3A\u54EA\u51E0\u4E2A\u540D\u5B57\u4E00\u6B21\u5217\u5168\uFF09",
59394
59426
  " env:",
59395
59427
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
59396
59428
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
59397
59429
  " run: node clawos/cloud-host/pipeline/check-secrets.mjs",
59398
59430
  "",
59399
- " - uses: pnpm/action-setup@v4",
59400
- " if: steps.plan.outputs.asset_builds != ''",
59401
- " with:",
59402
- " version: 10",
59403
- "",
59404
- " - uses: actions/setup-node@v4",
59405
- " if: steps.plan.outputs.asset_builds != ''",
59406
- " with:",
59407
- " node-version: 20",
59408
- " cache: pnpm",
59409
- " cache-dependency-path: clawos/clawd/pnpm-lock.yaml",
59410
- "",
59411
- " - name: \u6784\u968F\u884C\u8D44\u4EA7\uFF08\u6E05\u5355\u91CC\u70B9\u8FC7\u540D\u3001\u4E14\u662F\u4ED3\u5E93\u6784\u5EFA\u4EA7\u7269\u7684\u90A3\u4E9B\uFF09",
59412
- " # \u547D\u4EE4\u6765\u81EA assets.json\uFF0C\u5B83\u81EA\u5DF1\u5E26\u88C5\u4F9D\u8D56\u90A3\u4E00\u6B65\u3002< /dev/null\uFF1A\u522B\u8BA9\u67D0\u6761\u547D\u4EE4\u628A here-string \u91CC\u5269\u4E0B\u7684\u884C\u5F53 stdin \u5403\u6389",
59413
- " if: steps.plan.outputs.asset_builds != ''",
59414
- " working-directory: clawos",
59431
+ " - name: Dockerfile \u5728\u3001\u4E14\u62F7\u5230\u7684\u662F\u8FD9\u4E2A persona \u7684\u76EE\u5F55",
59432
+ " # Dockerfile \u7531 clawd \u53D1\u5E03\u65F6\u5199\uFF08\u540C\u8FD9\u4EFD workflow\uFF09\uFF0CACR \u6309\u5B83\u6784\u3002\u76EE\u5F55\u540D\u90A3\u4E00\u6BB5\u8981\u4E0E deploy-file \u7B97\u51FA\u7684 persona_id \u4E00\u81F4\uFF1A",
59433
+ " # \u4E24\u8FB9\u5404\u6709\u4E00\u4EFD\u540C\u6837\u7684\u540D\u5B57\u6E05\u6D17\uFF0C\u8FD9\u91CC\u662F\u5B83\u4EEC\u552F\u4E00\u7684\u4EA4\u6C47\u70B9\u3002",
59415
59434
  " run: |",
59416
- " set -e",
59417
- " while IFS= read -r cmd; do",
59418
- ' [ -n "$cmd" ] || continue',
59419
- ' echo "$ $cmd"',
59420
- ' bash -c "$cmd" < /dev/null',
59421
- " done <<< '${{ steps.plan.outputs.asset_builds }}'",
59435
+ " test -f persona/Dockerfile \\",
59436
+ ' || { echo "\u2717 \u4ED3\u5E93\u91CC\u6CA1\u6709 Dockerfile\uFF1A\u8FD9\u6B21\u63A8\u9001\u4E0D\u662F clawd \u53D1\u5E03\u7684\uFF08\u6216 clawd \u592A\u65E7\uFF09\uFF1B\u56DE clawd \u7684\u4E0A\u4E91\u9875\u9762\u91CD\u65B0\u53D1\u5E03" >&2; exit 1; }',
59437
+ " grep -qF '/clawd/personas/${{ steps.plan.outputs.persona_id }}/' persona/Dockerfile \\",
59438
+ ' || { echo "\u2717 Dockerfile \u62F7\u5230\u7684\u76EE\u5F55\u4E0D\u662F /clawd/personas/${{ steps.plan.outputs.persona_id }}/" >&2; exit 1; }',
59422
59439
  "",
59423
- " - name: Login to ACR",
59424
- " uses: aliyun/acr-login@v1",
59425
- " with:",
59426
- " login-server: ${{ env.REGISTRY }}",
59427
- ' username: "${{ secrets.ALI_DOCKER_USERNAME }}"',
59428
- ' password: "${{ secrets.ALI_DOCKER_PASSWORD }}"',
59429
- "",
59430
- " - name: \u6784 persona \u5C42",
59431
- " # \u6784\u5EFA\u5668\u6574\u76EE\u5F55\u62F7\uFF0C`.git` \u4E0D\u662F\u4EBA\u683C\uFF0C\u5148\u5220\u3002\u5E95\u5EA7\u7528 :base \u79FB\u52A8 tag\u2014\u2014runner \u6BCF\u6B21\u90FD\u662F\u5E72\u51C0\u673A\u5668\u3001",
59432
- " # \u5FC5\u7136\u62C9\u6700\u65B0\uFF1Bpersona \u5C42\u81EA\u5DF1\u7684 tag \u5E26 commit sha\u3001\u4E0D\u53EF\u53D8\uFF0C\u96C6\u7FA4\u6309\u5B83\u62C9\u6CA1\u6709\u6B67\u4E49\u3002",
59440
+ " - name: \u88C5 aliyun CLI\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09",
59441
+ " env:",
59442
+ " GH_TOKEN: ${{ github.token }}",
59433
59443
  " run: |",
59434
- " rm -rf persona/.git",
59435
- " node clawos/cloud-host/provision/build-image.mjs \\",
59436
- " --manifest persona/.clawd/deploy.json \\",
59437
- ' --from "$REGISTRY/$IMAGE_NAME:base-${{ steps.plan.outputs.engine }}" \\',
59438
- " --persona-dir persona \\",
59439
- // persona 在镜像里落 /clawd/personas/<id>/(与本机同构),id 是 gateway 登记的名字;同 smoke / register 用的那个输出
59440
- " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
59441
- ' --tag "$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
59444
+ " TAGNAME=$(gh release view --repo aliyun/aliyun-cli --json tagName -q .tagName)",
59445
+ // 不用 ${TAGNAME#v} 这种带花括号的展开:这份模板里 `${` 只许出现在 GitHub 表达式里(spec 守着)
59446
+ ' VER=$(printf %s "$TAGNAME" | sed s/^v//)',
59447
+ ' curl -fsSL -o /tmp/aliyun-cli.tgz "https://github.com/aliyun/aliyun-cli/releases/download/$TAGNAME/aliyun-cli-linux-$VER-amd64.tgz"',
59448
+ " sudo tar -xzf /tmp/aliyun-cli.tgz -C /usr/local/bin",
59449
+ " aliyun version",
59442
59450
  "",
59443
- " - name: \u955C\u50CF\u65AD\u8A00\uFF08\u6E05\u5355\u91CC\u8981\u88C5\u7684\u90FD\u5728\u3001bundle \u91CC persona \u5728\uFF09",
59444
- " # /opt/versions.sh \u6BCF\u884C\u90FD\u4EE5 `|| echo` \u6536\u5C3E\u3001\u6C38\u8FDC exit 0\uFF0C\u53EA\u80FD\u9A8C\u8F93\u51FA\uFF1A\u6BB5\u6570\u8981\u7B49\u4E8E\u6E05\u5355 packages \u7684",
59445
- " # \u6761\u6570\uFF0C\u6BCF\u6BB5\u4E0B\u9762\u8981\u6709\u7248\u672C\u53F7\u3002\u955C\u50CF ENTRYPOINT \u662F sh -c\uFF0C\u547D\u4EE4\u8981\u4F5C\u4E3A\u4E00\u4E2A\u5B57\u7B26\u4E32\u4F20\u3002",
59451
+ " - name: \u8BA9 ACR \u4ECE\u672C\u4ED3\u5E93\u6784\uFF08\u9996\u6B21\u53D1\u5E03\u5148\u5EFA ACR \u4ED3\u5E93\u4E0E\u89C4\u5219\uFF1B\u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\uFF09",
59452
+ " # ACR \u6784\u7684\u662F main \u5F53\u524D\u7684 tip\u3001\u4E0D\u662F github.sha\uFF1Atip \u5DF2\u7ECF\u4E0D\u662F\u672C\u6B21 commit \u65F6\u76F4\u63A5\u7EA2\uFF0C\u8BA9\u66F4\u65B0\u7684\u90A3\u6B21 run \u53BB\u6784\u3001\u53BB\u767B\u8BB0\u3002",
59453
+ " # \u81EA\u52A8\u6784\u5EFA\u5173\u7740\uFF1A\u53EA\u6709\u8FD9\u91CC\u89E6\u53D1\u3001webhook \u4E0D\u6784\uFF0C\u300C\u6784 \u2192 \u5192\u70DF \u2192 \u767B\u8BB0\u300D\u624D\u662F\u4E00\u6761\u6709\u5E8F\u7684\u94FE\u3002",
59454
+ " # \u6784\u51FA\u7684\u662F\u54EA\u4E2A commit \u7531 acr.mjs wait \u6309\u6784\u5EFA\u8BB0\u5F55 + \u65E5\u5FD7\u91CC\u7684 commit \u6838\uFF0C\u4E0D\u770B\u955C\u50CF\u7684\u65F6\u95F4\uFF08\u7F13\u5B58\u547D\u4E2D\u65F6\u90A3\u662F\u8001\u7684\uFF09\u3002",
59455
+ " env:",
59456
+ " ALIBABA_CLOUD_ACCESS_KEY_ID: ${{ secrets.ALI_ACS_ACCESS_KEY_ID }}",
59457
+ " ALIBABA_CLOUD_ACCESS_KEY_SECRET: ${{ secrets.ALI_ACS_ACCESS_KEY_SECRET }}",
59446
59458
  " run: |",
59447
- ' IMG="$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
59448
- ` OUT=$(docker run --rm "$IMG" '/opt/versions.sh')`,
59449
- ' echo "$OUT"',
59450
- ` WANT=$(node -e 'const m=JSON.parse(require("fs").readFileSync("persona/.clawd/deploy.json","utf8"));const b=m.manifest??m;console.log((b.packages??b.clis??[]).length)')`,
59451
- ` echo "$OUT" | awk -v want="$WANT" '`,
59452
- ' /^--- / { name=$2; if ((getline v) <= 0) v=""; n++',
59453
- ' if (v !~ /[0-9]+\\.[0-9]+/) { printf " \u2717 %s \u6CA1\u62A5\u51FA\u7248\u672C\u53F7\uFF1A%s\\n", name, v > "/dev/stderr"; bad++ } }',
59454
- ' END { if (n != want) { printf " \u2717 \u955C\u50CF\u91CC\u53EA\u6709 %d \u6BB5\u7248\u672C\u8F93\u51FA\uFF0C\u6E05\u5355\u8981\u88C5 %d \u4E2A\\n", n, want > "/dev/stderr"; bad++ }',
59455
- " exit bad ? 1 : 0 }'",
59456
- ' echo " \u2713 \u6E05\u5355\u91CC\u8981\u88C5\u7684 $WANT \u4E2A\u90FD\u5728\u4E14\u62A5\u5F97\u51FA\u7248\u672C"',
59457
- ` docker run --rm "$IMG" 'test -d /clawd/personas/\${{ steps.plan.outputs.persona_id }}' \\`,
59458
- ' || { echo " \u2717 /clawd/personas/${{ steps.plan.outputs.persona_id }} \u4E0D\u5728" >&2; exit 1; }',
59459
- ' echo " \u2713 persona \u76EE\u5F55\u5728"',
59459
+ // pipefail:ls-remote 那条管道里 cut 永远退 0,没有 pipefail 的话 ls-remote 挂了 TIP 是空串、红在「main 已经推进到 」这句误导人的话上
59460
+ " set -eo pipefail",
59461
+ ' REPO="$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}"',
59462
+ ' node clawos/cloud-host/pipeline/acr.mjs ensure-repo --repo "$REPO" \\',
59463
+ " --source '${{ github.repository }}' --location / --dockerfile Dockerfile --branch main --tag latest \\",
59464
+ " --summary 'clawd persona ${{ github.event.repository.name }}'",
59465
+ " TIP=$(git -C persona ls-remote origin refs/heads/main | cut -f1)",
59466
+ ` [ "$TIP" = '\${{ github.sha }}' ] \\`,
59467
+ ' || { echo "\u2717 main \u5DF2\u7ECF\u63A8\u8FDB\u5230 $TIP\uFF0C\u672C\u6B21 ${{ github.sha }} \u4E0D\u518D\u6784\uFF1B\u7B49\u65B0\u7684\u90A3\u6B21 run" >&2; exit 1; }',
59468
+ ' node clawos/cloud-host/pipeline/acr.mjs trigger --repo "$REPO" --tag latest',
59469
+ ` node clawos/cloud-host/pipeline/acr.mjs wait --repo "$REPO" --tag latest --commit '\${{ github.sha }}' --timeout-sec 1800`,
59460
59470
  "",
59461
- " - name: Push to ACR",
59462
- ' run: docker push "$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
59471
+ ...ACR_LOGIN_STEPS,
59472
+ " - name: \u955C\u50CF = \u672C\u6B21 commit \u6784\u51FA\u7684\u90A3\u4EFD\uFF08digest\uFF1B\u53EA\u6253\u65E5\u5FD7\uFF0Csmoke / deploy \u5404\u81EA\u518D\u89E3\u6790\u4E00\u6B21\uFF09",
59473
+ ` run: node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY"`,
59463
59474
  "",
59464
59475
  " smoke:",
59465
59476
  " name: smoke",
@@ -59468,9 +59479,10 @@ var L2 = [
59468
59479
  " timeout-minutes: 20",
59469
59480
  " steps:",
59470
59481
  ...CONTRACT_STEPS,
59482
+ ...ACR_LOGIN_STEPS,
59471
59483
  " - name: \u4E34\u65F6\u767B\u8BB0 \u2192 \u8D77\u4E00\u6B21 Pod \u2192 \u64A4\u9500",
59472
59484
  " # \u767B\u8BB0\u6B63\u5F0F\u53EA\u662F\u5F80 gateway \u5199\u4E00\u884C\uFF0Cgateway \u4E0D\u78B0\u955C\u50CF\uFF1B\u96C6\u7FA4\u62C9\u955C\u50CF\u53D1\u751F\u5728\u7B2C\u4E00\u4E2A\u4EFB\u52A1\u5230\u6765\u65F6\u3002",
59473
- " # \u6CA1\u6709\u8FD9\u4E00\u6B65\uFF0C\u6D41\u6C34\u7EBF\u7EFF\u4E86\u53EA\u4EE3\u8868\u300C\u767B\u8BB0\u4E86\u300D\u3002",
59485
+ " # \u6CA1\u6709\u8FD9\u4E00\u6B65\uFF0C\u6D41\u6C34\u7EBF\u7EFF\u4E86\u53EA\u4EE3\u8868\u300C\u767B\u8BB0\u4E86\u300D\u3002\u955C\u50CF\u7528 digest\uFF08\u96C6\u7FA4 Job \u662F IfNotPresent\uFF0C\u79FB\u52A8 tag \u4F1A\u4E00\u76F4\u8DD1\u65E7\u7684\uFF09\u3002",
59474
59486
  // 模型 / 档位 / 连接器 smoke 也要:试跑那次要跟正式那次拿到同一份,否则验的不是将要上线的东西。
59475
59487
  // 名字形状 deploy-file.mjs 已卡死(persona_id [a-z0-9-]、model / effort [A-Za-z0-9._/-](`/` 是 pi 的 provider/id,不是元字符)、size 四档枚举、task_concurrency 正整数、connectors 无单引号
59476
59488
  // 无换行),所以单引号包住直接拼进命令行是安全的。
@@ -59480,8 +59492,10 @@ var L2 = [
59480
59492
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
59481
59493
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
59482
59494
  " run: |",
59495
+ " set -e",
59496
+ RESOLVE_LINE,
59483
59497
  " node clawos/cloud-host/pipeline/smoke.mjs \\",
59484
- " --image '${{ steps.plan.outputs.image }}' \\",
59498
+ ' --image "$IMAGE_REF" \\',
59485
59499
  " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
59486
59500
  " --model '${{ steps.plan.outputs.model }}' \\",
59487
59501
  " --effort '${{ steps.plan.outputs.effort }}' \\",
@@ -59499,6 +59513,7 @@ var L2 = [
59499
59513
  " environment: production",
59500
59514
  " steps:",
59501
59515
  ...CONTRACT_STEPS,
59516
+ ...ACR_LOGIN_STEPS,
59502
59517
  " - name: \u767B\u8BB0\u6B63\u5F0F",
59503
59518
  " env:",
59504
59519
  " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_GATEWAY_URL }}",
@@ -59506,8 +59521,10 @@ var L2 = [
59506
59521
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
59507
59522
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
59508
59523
  " run: |",
59524
+ " set -e",
59525
+ RESOLVE_LINE,
59509
59526
  " node clawos/cloud-host/pipeline/register.mjs \\",
59510
- " --image '${{ steps.plan.outputs.image }}' \\",
59527
+ ' --image "$IMAGE_REF" \\',
59511
59528
  " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
59512
59529
  " --model '${{ steps.plan.outputs.model }}' \\",
59513
59530
  " --effort '${{ steps.plan.outputs.effort }}' \\",
@@ -59637,6 +59654,10 @@ async function writeWorkflow(dir) {
59637
59654
  await import_promises5.default.mkdir(import_node_path34.default.dirname(wf), { recursive: true });
59638
59655
  await import_promises5.default.writeFile(wf, WORKFLOW_TEMPLATE);
59639
59656
  }
59657
+ async function writeDockerfile(dir, personaId2) {
59658
+ await import_promises5.default.writeFile(import_node_path34.default.join(dir, DOCKERFILE_PATH), renderDockerfile(personaId2));
59659
+ await import_promises5.default.writeFile(import_node_path34.default.join(dir, DOCKERIGNORE_PATH), DOCKERIGNORE_TEMPLATE);
59660
+ }
59640
59661
  var RepoAlreadyExistsError = class extends RepoError {
59641
59662
  constructor(slug) {
59642
59663
  super(`\u7EC4\u7EC7\u91CC\u5DF2\u7ECF\u6709 https://github.com/${slug} \u4E86`);
@@ -59725,6 +59746,7 @@ async function release(exec, api, args) {
59725
59746
  await api.enableActions(repoSlug(info.url));
59726
59747
  await writeGitignore(args.dir);
59727
59748
  await writeWorkflow(args.dir);
59749
+ await writeDockerfile(args.dir, personaIdOf(repoSlug(info.url).split("/").pop() ?? ""));
59728
59750
  const identity = await identityArgs(exec, args.dir);
59729
59751
  await mustGit(exec, args.dir, ["add", "-A"], "\u6682\u5B58\u6587\u4EF6");
59730
59752
  const stamp = new Date(args.now()).toISOString();
@@ -71337,7 +71359,7 @@ function computeMethodAccess(args) {
71337
71359
  }
71338
71360
 
71339
71361
  // src/version.ts
71340
- var version = "0.2.568".length > 0 ? "0.2.568" : "dev";
71362
+ var version = "0.2.569".length > 0 ? "0.2.569" : "dev";
71341
71363
 
71342
71364
  // src/cli-probe/probe.ts
71343
71365
  var fs78 = __toESM(require("fs"), 1);
@@ -24796,6 +24796,18 @@ var z2 = external_exports.object({ version: external_exports.literal(2), scans:
24796
24796
  // src/deploy/templates.ts
24797
24797
  var CLAWOS_REPO = "ottin4ttc/clawos";
24798
24798
  var CLAWOS_REF = "release";
24799
+ var ACR_REGISTRY = "registry.cn-hangzhou.aliyuncs.com";
24800
+ var ACR_VPC_REGISTRY = "registry-vpc.cn-hangzhou.aliyuncs.com";
24801
+ var ACR_NAMESPACE = "ttc-prod";
24802
+ var BASE_IMAGE = `${ACR_REGISTRY}/${ACR_NAMESPACE}/clawd-persona-base:release`;
24803
+ var DOCKERIGNORE_TEMPLATE = [
24804
+ "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF08\u540C Dockerfile\uFF09\u3002",
24805
+ ".git",
24806
+ ".github",
24807
+ "Dockerfile",
24808
+ ".dockerignore",
24809
+ ""
24810
+ ].join("\n");
24799
24811
  var PLAN_STEP = [
24800
24812
  " - name: \u8BFB\u90E8\u7F72\u6587\u4EF6",
24801
24813
  " id: plan",
@@ -24803,9 +24815,7 @@ var PLAN_STEP = [
24803
24815
  " node clawos/cloud-host/pipeline/deploy-file.mjs \\",
24804
24816
  " --persona-dir persona \\",
24805
24817
  " --repo-name '${{ github.event.repository.name }}' \\",
24806
- " --sha '${{ github.sha }}' \\",
24807
- ' --image-repo "$VPC_REGISTRY/$IMAGE_NAME" \\',
24808
- ' --assets clawos/cloud-host/provision/manifests/assets.json >> "$GITHUB_OUTPUT"',
24818
+ ` --sha '\${{ github.sha }}' >> "$GITHUB_OUTPUT"`,
24809
24819
  ""
24810
24820
  ];
24811
24821
  var CONTRACT_STEPS = [
@@ -24815,7 +24825,7 @@ var CONTRACT_STEPS = [
24815
24825
  " path: persona",
24816
24826
  " sparse-checkout: .clawd",
24817
24827
  "",
24818
- " - name: Checkout clawos\uFF08\u6D41\u6C34\u7EBF\u811A\u672C + \u5B83\u5F15\u7684 k8s \u540D\u5B57\u6E05\u6D17 / \u8D44\u4EA7\u6E05\u5355\uFF09",
24828
+ " - name: Checkout clawos\uFF08\u6D41\u6C34\u7EBF\u811A\u672C + \u5B83\u5F15\u7684 k8s \u540D\u5B57\u6E05\u6D17\uFF09",
24819
24829
  " uses: actions/checkout@v4",
24820
24830
  " with:",
24821
24831
  " repository: ${{ env.CLAWOS_REPO }}",
@@ -24825,19 +24835,31 @@ var CONTRACT_STEPS = [
24825
24835
  " sparse-checkout: |",
24826
24836
  " cloud-host/pipeline",
24827
24837
  " cloud-host/k8s",
24828
- " cloud-host/provision/manifests",
24829
24838
  "",
24830
24839
  ...PLAN_STEP
24831
24840
  ];
24841
+ var ACR_LOGIN_STEPS = [
24842
+ " - name: Login to ACR\uFF08\u89E3\u6790\u955C\u50CF digest \u8981 docker \u51ED\u636E\uFF09",
24843
+ " uses: aliyun/acr-login@v1",
24844
+ " with:",
24845
+ " login-server: ${{ env.REGISTRY }}",
24846
+ ' username: "${{ secrets.ALI_DOCKER_USERNAME }}"',
24847
+ ' password: "${{ secrets.ALI_DOCKER_PASSWORD }}"',
24848
+ ""
24849
+ ];
24850
+ var IMAGE_LATEST = '"$REGISTRY/$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}:latest"';
24851
+ var RESOLVE_LINE = ` IMAGE_REF=$(node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY")`;
24832
24852
  var L = [
24833
24853
  "name: clawd deploy",
24834
24854
  "",
24835
24855
  "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF1A\u6BCF\u6B21\u300C\u53D1\u5E03\u300D\u90FD\u4F1A\u7528\u5F53\u524D\u6A21\u677F\u91CD\u5199\u8FD9\u4EFD\u6587\u4EF6\u518D\u63D0\u4EA4\uFF0C\u624B\u6539\u4F1A\u88AB\u76D6\u6389\u3002",
24836
- "# \u4E09\u6BB5\uFF1Abuild \u6784 persona \u5C42\u955C\u50CF\u63A8 ACR \u2192 smoke \u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21 \u2192 deploy \u5728 gateway \u767B\u8BB0\u6210\u6B63\u5F0F\u3002",
24837
- "# \u6784\u5EFA\u5668 / \u6D41\u6C34\u7EBF\u811A\u672C / \u968F\u884C\u8D44\u4EA7\u5728 ottin4ttc/clawos \u4ED3\u5E93\u91CC\uFF0C\u8FD9\u91CC checkout \u4E00\u4EFD\u6765\u7528\u3002",
24856
+ "# \u4E09\u6BB5\uFF1Abuild \u8BA9 ACR \u4ECE\u8FD9\u4E2A\u4ED3\u5E93\u6784 persona \u955C\u50CF\uFF08Dockerfile \u4E5F\u662F clawd \u5199\u7684\uFF09\u2192 smoke \u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21 \u2192 deploy \u5728 gateway \u767B\u8BB0\u6210\u6B63\u5F0F\u3002",
24857
+ "# \u955C\u50CF\u4E0D\u5728 runner \u4E0A\u6784\u3001\u4E5F\u4E0D\u4ECE runner \u63A8\uFF1AACR \u4E2A\u4EBA\u7248\u4ED3\u5E93 ttc-prod/<persona_id> \u6302\u7740\u8FD9\u4E2A GitHub \u4ED3\u5E93\u5F53\u4EE3\u7801\u6E90\uFF08\u9996\u6B21\u53D1\u5E03\u65F6\u81EA\u5EFA\uFF09\uFF0C",
24858
+ "# build \u6BB5\u53EA\u662F\u300C\u89E6\u53D1 \u2192 \u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\u300D\uFF1Bsmoke / deploy \u5404\u81EA\u628A :latest \u89E3\u6790\u6210 digest \u518D\u7528\u3002\u6D41\u6C34\u7EBF\u811A\u672C\u5728 ottin4ttc/clawos \u4ED3\u5E93\u91CC\u3002",
24838
24859
  "#",
24839
- "# \u8981\u7684\u7EC4\u7EC7\u7EA7 Secrets\uFF1AALI_DOCKER_USERNAME / ALI_DOCKER_PASSWORD\uFF08\u63A8 ACR\uFF09\u3001CLAWOS_READ_TOKEN",
24840
- "#\uFF08\u8BFB clawos \u4ED3\u5E93\uFF09\u3001CLAWD_GATEWAY_ADMIN_KEY\uFF1B\u7EC4\u7EC7\u7EA7 Variable\uFF1ACLAWD_GATEWAY_URL\u3002",
24860
+ "# \u8981\u7684\u7EC4\u7EC7\u7EA7 Secrets\uFF1AALI_ACS_ACCESS_KEY_ID / ALI_ACS_ACCESS_KEY_SECRET\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09\u3001",
24861
+ "# ALI_DOCKER_USERNAME / ALI_DOCKER_PASSWORD\uFF08\u89E3\u6790\u955C\u50CF digest\uFF09\u3001CLAWOS_READ_TOKEN\uFF08\u8BFB clawos \u4ED3\u5E93\uFF09\u3001CLAWD_GATEWAY_ADMIN_KEY\uFF1B",
24862
+ "# \u7EC4\u7EC7\u7EA7 Variable\uFF1ACLAWD_GATEWAY_URL\u3002",
24841
24863
  "# \u4ED3\u5E93\u7EA7\u540C\u540D\u914D\u7F6E\u4F1A\u76D6\u8FC7\u7EC4\u7EC7\u7EA7\u2014\u2014\u67D0\u4E2A persona \u8981\u6307\u5230\u53E6\u4E00\u53F0 gateway\uFF0C\u5728\u81EA\u5DF1\u4ED3\u5E93\u91CC\u914D\u5373\u53EF\u3002",
24842
24864
  "",
24843
24865
  "on:",
@@ -24850,9 +24872,9 @@ var L = [
24850
24872
  " group: persona-cloud-${{ github.repository }}",
24851
24873
  "",
24852
24874
  "env:",
24853
- " REGISTRY: registry.cn-hangzhou.aliyuncs.com",
24854
- " VPC_REGISTRY: registry-vpc.cn-hangzhou.aliyuncs.com",
24855
- " IMAGE_NAME: ttc-prod/clawd-persona-cloud",
24875
+ ` REGISTRY: ${ACR_REGISTRY}`,
24876
+ ` VPC_REGISTRY: ${ACR_VPC_REGISTRY}`,
24877
+ ` ACR_NAMESPACE: ${ACR_NAMESPACE}`,
24856
24878
  ` CLAWOS_REPO: ${CLAWOS_REPO}`,
24857
24879
  ` CLAWOS_REF: ${CLAWOS_REF}`,
24858
24880
  "",
@@ -24865,93 +24887,60 @@ var L = [
24865
24887
  // 中文说明归 clawd 的上云页面,这里保持机器好认。
24866
24888
  " name: build",
24867
24889
  " runs-on: ubuntu-latest",
24868
- " timeout-minutes: 30",
24869
- // 没有 outputs:——smoke / deploy 段自己读契约(文件头)。build 段整仓 checkout:构建器要拷整个 persona 目录。
24890
+ // ACR 个人版的构建按账号串行:底座(8 分钟)/ api 在前面排着时要等它们先构完。
24891
+ " timeout-minutes: 40",
24892
+ // 没有 outputs:——smoke / deploy 段自己读契约、自己解析 digest(文件头)。
24870
24893
  " steps:",
24871
- " - name: Checkout persona",
24872
- " uses: actions/checkout@v4",
24873
- " with:",
24874
- " path: persona",
24875
- "",
24876
- " - name: Checkout clawos\uFF08\u6784\u5EFA\u5668 / \u6D41\u6C34\u7EBF\u811A\u672C / \u968F\u884C\u8D44\u4EA7\uFF09",
24877
- " uses: actions/checkout@v4",
24878
- " with:",
24879
- " repository: ${{ env.CLAWOS_REPO }}",
24880
- " ref: ${{ env.CLAWOS_REF }}",
24881
- " token: ${{ secrets.CLAWOS_READ_TOKEN }}",
24882
- " path: clawos",
24883
- "",
24884
- ...PLAN_STEP,
24894
+ ...CONTRACT_STEPS,
24885
24895
  " - name: \u51ED\u636E\u9F50\u4E0D\u9F50\uFF08\u7F3A\u54EA\u51E0\u4E2A\u540D\u5B57\u4E00\u6B21\u5217\u5168\uFF09",
24886
24896
  " env:",
24887
24897
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24888
24898
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24889
24899
  " run: node clawos/cloud-host/pipeline/check-secrets.mjs",
24890
24900
  "",
24891
- " - uses: pnpm/action-setup@v4",
24892
- " if: steps.plan.outputs.asset_builds != ''",
24893
- " with:",
24894
- " version: 10",
24895
- "",
24896
- " - uses: actions/setup-node@v4",
24897
- " if: steps.plan.outputs.asset_builds != ''",
24898
- " with:",
24899
- " node-version: 20",
24900
- " cache: pnpm",
24901
- " cache-dependency-path: clawos/clawd/pnpm-lock.yaml",
24902
- "",
24903
- " - name: \u6784\u968F\u884C\u8D44\u4EA7\uFF08\u6E05\u5355\u91CC\u70B9\u8FC7\u540D\u3001\u4E14\u662F\u4ED3\u5E93\u6784\u5EFA\u4EA7\u7269\u7684\u90A3\u4E9B\uFF09",
24904
- " # \u547D\u4EE4\u6765\u81EA assets.json\uFF0C\u5B83\u81EA\u5DF1\u5E26\u88C5\u4F9D\u8D56\u90A3\u4E00\u6B65\u3002< /dev/null\uFF1A\u522B\u8BA9\u67D0\u6761\u547D\u4EE4\u628A here-string \u91CC\u5269\u4E0B\u7684\u884C\u5F53 stdin \u5403\u6389",
24905
- " if: steps.plan.outputs.asset_builds != ''",
24906
- " working-directory: clawos",
24901
+ " - name: Dockerfile \u5728\u3001\u4E14\u62F7\u5230\u7684\u662F\u8FD9\u4E2A persona \u7684\u76EE\u5F55",
24902
+ " # Dockerfile \u7531 clawd \u53D1\u5E03\u65F6\u5199\uFF08\u540C\u8FD9\u4EFD workflow\uFF09\uFF0CACR \u6309\u5B83\u6784\u3002\u76EE\u5F55\u540D\u90A3\u4E00\u6BB5\u8981\u4E0E deploy-file \u7B97\u51FA\u7684 persona_id \u4E00\u81F4\uFF1A",
24903
+ " # \u4E24\u8FB9\u5404\u6709\u4E00\u4EFD\u540C\u6837\u7684\u540D\u5B57\u6E05\u6D17\uFF0C\u8FD9\u91CC\u662F\u5B83\u4EEC\u552F\u4E00\u7684\u4EA4\u6C47\u70B9\u3002",
24907
24904
  " run: |",
24908
- " set -e",
24909
- " while IFS= read -r cmd; do",
24910
- ' [ -n "$cmd" ] || continue',
24911
- ' echo "$ $cmd"',
24912
- ' bash -c "$cmd" < /dev/null',
24913
- " done <<< '${{ steps.plan.outputs.asset_builds }}'",
24914
- "",
24915
- " - name: Login to ACR",
24916
- " uses: aliyun/acr-login@v1",
24917
- " with:",
24918
- " login-server: ${{ env.REGISTRY }}",
24919
- ' username: "${{ secrets.ALI_DOCKER_USERNAME }}"',
24920
- ' password: "${{ secrets.ALI_DOCKER_PASSWORD }}"',
24905
+ " test -f persona/Dockerfile \\",
24906
+ ' || { echo "\u2717 \u4ED3\u5E93\u91CC\u6CA1\u6709 Dockerfile\uFF1A\u8FD9\u6B21\u63A8\u9001\u4E0D\u662F clawd \u53D1\u5E03\u7684\uFF08\u6216 clawd \u592A\u65E7\uFF09\uFF1B\u56DE clawd \u7684\u4E0A\u4E91\u9875\u9762\u91CD\u65B0\u53D1\u5E03" >&2; exit 1; }',
24907
+ " grep -qF '/clawd/personas/${{ steps.plan.outputs.persona_id }}/' persona/Dockerfile \\",
24908
+ ' || { echo "\u2717 Dockerfile \u62F7\u5230\u7684\u76EE\u5F55\u4E0D\u662F /clawd/personas/${{ steps.plan.outputs.persona_id }}/" >&2; exit 1; }',
24921
24909
  "",
24922
- " - name: \u6784 persona \u5C42",
24923
- " # \u6784\u5EFA\u5668\u6574\u76EE\u5F55\u62F7\uFF0C`.git` \u4E0D\u662F\u4EBA\u683C\uFF0C\u5148\u5220\u3002\u5E95\u5EA7\u7528 :base \u79FB\u52A8 tag\u2014\u2014runner \u6BCF\u6B21\u90FD\u662F\u5E72\u51C0\u673A\u5668\u3001",
24924
- " # \u5FC5\u7136\u62C9\u6700\u65B0\uFF1Bpersona \u5C42\u81EA\u5DF1\u7684 tag \u5E26 commit sha\u3001\u4E0D\u53EF\u53D8\uFF0C\u96C6\u7FA4\u6309\u5B83\u62C9\u6CA1\u6709\u6B67\u4E49\u3002",
24910
+ " - name: \u88C5 aliyun CLI\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09",
24911
+ " env:",
24912
+ " GH_TOKEN: ${{ github.token }}",
24925
24913
  " run: |",
24926
- " rm -rf persona/.git",
24927
- " node clawos/cloud-host/provision/build-image.mjs \\",
24928
- " --manifest persona/.clawd/deploy.json \\",
24929
- ' --from "$REGISTRY/$IMAGE_NAME:base-${{ steps.plan.outputs.engine }}" \\',
24930
- " --persona-dir persona \\",
24931
- // persona 在镜像里落 /clawd/personas/<id>/(与本机同构),id 是 gateway 登记的名字;同 smoke / register 用的那个输出
24932
- " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
24933
- ' --tag "$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
24914
+ " TAGNAME=$(gh release view --repo aliyun/aliyun-cli --json tagName -q .tagName)",
24915
+ // 不用 ${TAGNAME#v} 这种带花括号的展开:这份模板里 `${` 只许出现在 GitHub 表达式里(spec 守着)
24916
+ ' VER=$(printf %s "$TAGNAME" | sed s/^v//)',
24917
+ ' curl -fsSL -o /tmp/aliyun-cli.tgz "https://github.com/aliyun/aliyun-cli/releases/download/$TAGNAME/aliyun-cli-linux-$VER-amd64.tgz"',
24918
+ " sudo tar -xzf /tmp/aliyun-cli.tgz -C /usr/local/bin",
24919
+ " aliyun version",
24934
24920
  "",
24935
- " - name: \u955C\u50CF\u65AD\u8A00\uFF08\u6E05\u5355\u91CC\u8981\u88C5\u7684\u90FD\u5728\u3001bundle \u91CC persona \u5728\uFF09",
24936
- " # /opt/versions.sh \u6BCF\u884C\u90FD\u4EE5 `|| echo` \u6536\u5C3E\u3001\u6C38\u8FDC exit 0\uFF0C\u53EA\u80FD\u9A8C\u8F93\u51FA\uFF1A\u6BB5\u6570\u8981\u7B49\u4E8E\u6E05\u5355 packages \u7684",
24937
- " # \u6761\u6570\uFF0C\u6BCF\u6BB5\u4E0B\u9762\u8981\u6709\u7248\u672C\u53F7\u3002\u955C\u50CF ENTRYPOINT \u662F sh -c\uFF0C\u547D\u4EE4\u8981\u4F5C\u4E3A\u4E00\u4E2A\u5B57\u7B26\u4E32\u4F20\u3002",
24921
+ " - name: \u8BA9 ACR \u4ECE\u672C\u4ED3\u5E93\u6784\uFF08\u9996\u6B21\u53D1\u5E03\u5148\u5EFA ACR \u4ED3\u5E93\u4E0E\u89C4\u5219\uFF1B\u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\uFF09",
24922
+ " # ACR \u6784\u7684\u662F main \u5F53\u524D\u7684 tip\u3001\u4E0D\u662F github.sha\uFF1Atip \u5DF2\u7ECF\u4E0D\u662F\u672C\u6B21 commit \u65F6\u76F4\u63A5\u7EA2\uFF0C\u8BA9\u66F4\u65B0\u7684\u90A3\u6B21 run \u53BB\u6784\u3001\u53BB\u767B\u8BB0\u3002",
24923
+ " # \u81EA\u52A8\u6784\u5EFA\u5173\u7740\uFF1A\u53EA\u6709\u8FD9\u91CC\u89E6\u53D1\u3001webhook \u4E0D\u6784\uFF0C\u300C\u6784 \u2192 \u5192\u70DF \u2192 \u767B\u8BB0\u300D\u624D\u662F\u4E00\u6761\u6709\u5E8F\u7684\u94FE\u3002",
24924
+ " # \u6784\u51FA\u7684\u662F\u54EA\u4E2A commit \u7531 acr.mjs wait \u6309\u6784\u5EFA\u8BB0\u5F55 + \u65E5\u5FD7\u91CC\u7684 commit \u6838\uFF0C\u4E0D\u770B\u955C\u50CF\u7684\u65F6\u95F4\uFF08\u7F13\u5B58\u547D\u4E2D\u65F6\u90A3\u662F\u8001\u7684\uFF09\u3002",
24925
+ " env:",
24926
+ " ALIBABA_CLOUD_ACCESS_KEY_ID: ${{ secrets.ALI_ACS_ACCESS_KEY_ID }}",
24927
+ " ALIBABA_CLOUD_ACCESS_KEY_SECRET: ${{ secrets.ALI_ACS_ACCESS_KEY_SECRET }}",
24938
24928
  " run: |",
24939
- ' IMG="$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
24940
- ` OUT=$(docker run --rm "$IMG" '/opt/versions.sh')`,
24941
- ' echo "$OUT"',
24942
- ` WANT=$(node -e 'const m=JSON.parse(require("fs").readFileSync("persona/.clawd/deploy.json","utf8"));const b=m.manifest??m;console.log((b.packages??b.clis??[]).length)')`,
24943
- ` echo "$OUT" | awk -v want="$WANT" '`,
24944
- ' /^--- / { name=$2; if ((getline v) <= 0) v=""; n++',
24945
- ' if (v !~ /[0-9]+\\.[0-9]+/) { printf " \u2717 %s \u6CA1\u62A5\u51FA\u7248\u672C\u53F7\uFF1A%s\\n", name, v > "/dev/stderr"; bad++ } }',
24946
- ' END { if (n != want) { printf " \u2717 \u955C\u50CF\u91CC\u53EA\u6709 %d \u6BB5\u7248\u672C\u8F93\u51FA\uFF0C\u6E05\u5355\u8981\u88C5 %d \u4E2A\\n", n, want > "/dev/stderr"; bad++ }',
24947
- " exit bad ? 1 : 0 }'",
24948
- ' echo " \u2713 \u6E05\u5355\u91CC\u8981\u88C5\u7684 $WANT \u4E2A\u90FD\u5728\u4E14\u62A5\u5F97\u51FA\u7248\u672C"',
24949
- ` docker run --rm "$IMG" 'test -d /clawd/personas/\${{ steps.plan.outputs.persona_id }}' \\`,
24950
- ' || { echo " \u2717 /clawd/personas/${{ steps.plan.outputs.persona_id }} \u4E0D\u5728" >&2; exit 1; }',
24951
- ' echo " \u2713 persona \u76EE\u5F55\u5728"',
24929
+ // pipefail:ls-remote 那条管道里 cut 永远退 0,没有 pipefail 的话 ls-remote 挂了 TIP 是空串、红在「main 已经推进到 」这句误导人的话上
24930
+ " set -eo pipefail",
24931
+ ' REPO="$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}"',
24932
+ ' node clawos/cloud-host/pipeline/acr.mjs ensure-repo --repo "$REPO" \\',
24933
+ " --source '${{ github.repository }}' --location / --dockerfile Dockerfile --branch main --tag latest \\",
24934
+ " --summary 'clawd persona ${{ github.event.repository.name }}'",
24935
+ " TIP=$(git -C persona ls-remote origin refs/heads/main | cut -f1)",
24936
+ ` [ "$TIP" = '\${{ github.sha }}' ] \\`,
24937
+ ' || { echo "\u2717 main \u5DF2\u7ECF\u63A8\u8FDB\u5230 $TIP\uFF0C\u672C\u6B21 ${{ github.sha }} \u4E0D\u518D\u6784\uFF1B\u7B49\u65B0\u7684\u90A3\u6B21 run" >&2; exit 1; }',
24938
+ ' node clawos/cloud-host/pipeline/acr.mjs trigger --repo "$REPO" --tag latest',
24939
+ ` node clawos/cloud-host/pipeline/acr.mjs wait --repo "$REPO" --tag latest --commit '\${{ github.sha }}' --timeout-sec 1800`,
24952
24940
  "",
24953
- " - name: Push to ACR",
24954
- ' run: docker push "$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
24941
+ ...ACR_LOGIN_STEPS,
24942
+ " - name: \u955C\u50CF = \u672C\u6B21 commit \u6784\u51FA\u7684\u90A3\u4EFD\uFF08digest\uFF1B\u53EA\u6253\u65E5\u5FD7\uFF0Csmoke / deploy \u5404\u81EA\u518D\u89E3\u6790\u4E00\u6B21\uFF09",
24943
+ ` run: node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY"`,
24955
24944
  "",
24956
24945
  " smoke:",
24957
24946
  " name: smoke",
@@ -24960,9 +24949,10 @@ var L = [
24960
24949
  " timeout-minutes: 20",
24961
24950
  " steps:",
24962
24951
  ...CONTRACT_STEPS,
24952
+ ...ACR_LOGIN_STEPS,
24963
24953
  " - name: \u4E34\u65F6\u767B\u8BB0 \u2192 \u8D77\u4E00\u6B21 Pod \u2192 \u64A4\u9500",
24964
24954
  " # \u767B\u8BB0\u6B63\u5F0F\u53EA\u662F\u5F80 gateway \u5199\u4E00\u884C\uFF0Cgateway \u4E0D\u78B0\u955C\u50CF\uFF1B\u96C6\u7FA4\u62C9\u955C\u50CF\u53D1\u751F\u5728\u7B2C\u4E00\u4E2A\u4EFB\u52A1\u5230\u6765\u65F6\u3002",
24965
- " # \u6CA1\u6709\u8FD9\u4E00\u6B65\uFF0C\u6D41\u6C34\u7EBF\u7EFF\u4E86\u53EA\u4EE3\u8868\u300C\u767B\u8BB0\u4E86\u300D\u3002",
24955
+ " # \u6CA1\u6709\u8FD9\u4E00\u6B65\uFF0C\u6D41\u6C34\u7EBF\u7EFF\u4E86\u53EA\u4EE3\u8868\u300C\u767B\u8BB0\u4E86\u300D\u3002\u955C\u50CF\u7528 digest\uFF08\u96C6\u7FA4 Job \u662F IfNotPresent\uFF0C\u79FB\u52A8 tag \u4F1A\u4E00\u76F4\u8DD1\u65E7\u7684\uFF09\u3002",
24966
24956
  // 模型 / 档位 / 连接器 smoke 也要:试跑那次要跟正式那次拿到同一份,否则验的不是将要上线的东西。
24967
24957
  // 名字形状 deploy-file.mjs 已卡死(persona_id [a-z0-9-]、model / effort [A-Za-z0-9._/-](`/` 是 pi 的 provider/id,不是元字符)、size 四档枚举、task_concurrency 正整数、connectors 无单引号
24968
24958
  // 无换行),所以单引号包住直接拼进命令行是安全的。
@@ -24972,8 +24962,10 @@ var L = [
24972
24962
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24973
24963
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24974
24964
  " run: |",
24965
+ " set -e",
24966
+ RESOLVE_LINE,
24975
24967
  " node clawos/cloud-host/pipeline/smoke.mjs \\",
24976
- " --image '${{ steps.plan.outputs.image }}' \\",
24968
+ ' --image "$IMAGE_REF" \\',
24977
24969
  " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
24978
24970
  " --model '${{ steps.plan.outputs.model }}' \\",
24979
24971
  " --effort '${{ steps.plan.outputs.effort }}' \\",
@@ -24991,6 +24983,7 @@ var L = [
24991
24983
  " environment: production",
24992
24984
  " steps:",
24993
24985
  ...CONTRACT_STEPS,
24986
+ ...ACR_LOGIN_STEPS,
24994
24987
  " - name: \u767B\u8BB0\u6B63\u5F0F",
24995
24988
  " env:",
24996
24989
  " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_GATEWAY_URL }}",
@@ -24998,8 +24991,10 @@ var L = [
24998
24991
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24999
24992
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
25000
24993
  " run: |",
24994
+ " set -e",
24995
+ RESOLVE_LINE,
25001
24996
  " node clawos/cloud-host/pipeline/register.mjs \\",
25002
- " --image '${{ steps.plan.outputs.image }}' \\",
24997
+ ' --image "$IMAGE_REF" \\',
25003
24998
  " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
25004
24999
  " --model '${{ steps.plan.outputs.model }}' \\",
25005
25000
  " --effort '${{ steps.plan.outputs.effort }}' \\",
@@ -24796,6 +24796,18 @@ var z2 = external_exports.object({ version: external_exports.literal(2), scans:
24796
24796
  // src/deploy/templates.ts
24797
24797
  var CLAWOS_REPO = "ottin4ttc/clawos";
24798
24798
  var CLAWOS_REF = "release";
24799
+ var ACR_REGISTRY = "registry.cn-hangzhou.aliyuncs.com";
24800
+ var ACR_VPC_REGISTRY = "registry-vpc.cn-hangzhou.aliyuncs.com";
24801
+ var ACR_NAMESPACE = "ttc-prod";
24802
+ var BASE_IMAGE = `${ACR_REGISTRY}/${ACR_NAMESPACE}/clawd-persona-base:release`;
24803
+ var DOCKERIGNORE_TEMPLATE = [
24804
+ "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF08\u540C Dockerfile\uFF09\u3002",
24805
+ ".git",
24806
+ ".github",
24807
+ "Dockerfile",
24808
+ ".dockerignore",
24809
+ ""
24810
+ ].join("\n");
24799
24811
  var PLAN_STEP = [
24800
24812
  " - name: \u8BFB\u90E8\u7F72\u6587\u4EF6",
24801
24813
  " id: plan",
@@ -24803,9 +24815,7 @@ var PLAN_STEP = [
24803
24815
  " node clawos/cloud-host/pipeline/deploy-file.mjs \\",
24804
24816
  " --persona-dir persona \\",
24805
24817
  " --repo-name '${{ github.event.repository.name }}' \\",
24806
- " --sha '${{ github.sha }}' \\",
24807
- ' --image-repo "$VPC_REGISTRY/$IMAGE_NAME" \\',
24808
- ' --assets clawos/cloud-host/provision/manifests/assets.json >> "$GITHUB_OUTPUT"',
24818
+ ` --sha '\${{ github.sha }}' >> "$GITHUB_OUTPUT"`,
24809
24819
  ""
24810
24820
  ];
24811
24821
  var CONTRACT_STEPS = [
@@ -24815,7 +24825,7 @@ var CONTRACT_STEPS = [
24815
24825
  " path: persona",
24816
24826
  " sparse-checkout: .clawd",
24817
24827
  "",
24818
- " - name: Checkout clawos\uFF08\u6D41\u6C34\u7EBF\u811A\u672C + \u5B83\u5F15\u7684 k8s \u540D\u5B57\u6E05\u6D17 / \u8D44\u4EA7\u6E05\u5355\uFF09",
24828
+ " - name: Checkout clawos\uFF08\u6D41\u6C34\u7EBF\u811A\u672C + \u5B83\u5F15\u7684 k8s \u540D\u5B57\u6E05\u6D17\uFF09",
24819
24829
  " uses: actions/checkout@v4",
24820
24830
  " with:",
24821
24831
  " repository: ${{ env.CLAWOS_REPO }}",
@@ -24825,19 +24835,31 @@ var CONTRACT_STEPS = [
24825
24835
  " sparse-checkout: |",
24826
24836
  " cloud-host/pipeline",
24827
24837
  " cloud-host/k8s",
24828
- " cloud-host/provision/manifests",
24829
24838
  "",
24830
24839
  ...PLAN_STEP
24831
24840
  ];
24841
+ var ACR_LOGIN_STEPS = [
24842
+ " - name: Login to ACR\uFF08\u89E3\u6790\u955C\u50CF digest \u8981 docker \u51ED\u636E\uFF09",
24843
+ " uses: aliyun/acr-login@v1",
24844
+ " with:",
24845
+ " login-server: ${{ env.REGISTRY }}",
24846
+ ' username: "${{ secrets.ALI_DOCKER_USERNAME }}"',
24847
+ ' password: "${{ secrets.ALI_DOCKER_PASSWORD }}"',
24848
+ ""
24849
+ ];
24850
+ var IMAGE_LATEST = '"$REGISTRY/$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}:latest"';
24851
+ var RESOLVE_LINE = ` IMAGE_REF=$(node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY")`;
24832
24852
  var L = [
24833
24853
  "name: clawd deploy",
24834
24854
  "",
24835
24855
  "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF1A\u6BCF\u6B21\u300C\u53D1\u5E03\u300D\u90FD\u4F1A\u7528\u5F53\u524D\u6A21\u677F\u91CD\u5199\u8FD9\u4EFD\u6587\u4EF6\u518D\u63D0\u4EA4\uFF0C\u624B\u6539\u4F1A\u88AB\u76D6\u6389\u3002",
24836
- "# \u4E09\u6BB5\uFF1Abuild \u6784 persona \u5C42\u955C\u50CF\u63A8 ACR \u2192 smoke \u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21 \u2192 deploy \u5728 gateway \u767B\u8BB0\u6210\u6B63\u5F0F\u3002",
24837
- "# \u6784\u5EFA\u5668 / \u6D41\u6C34\u7EBF\u811A\u672C / \u968F\u884C\u8D44\u4EA7\u5728 ottin4ttc/clawos \u4ED3\u5E93\u91CC\uFF0C\u8FD9\u91CC checkout \u4E00\u4EFD\u6765\u7528\u3002",
24856
+ "# \u4E09\u6BB5\uFF1Abuild \u8BA9 ACR \u4ECE\u8FD9\u4E2A\u4ED3\u5E93\u6784 persona \u955C\u50CF\uFF08Dockerfile \u4E5F\u662F clawd \u5199\u7684\uFF09\u2192 smoke \u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21 \u2192 deploy \u5728 gateway \u767B\u8BB0\u6210\u6B63\u5F0F\u3002",
24857
+ "# \u955C\u50CF\u4E0D\u5728 runner \u4E0A\u6784\u3001\u4E5F\u4E0D\u4ECE runner \u63A8\uFF1AACR \u4E2A\u4EBA\u7248\u4ED3\u5E93 ttc-prod/<persona_id> \u6302\u7740\u8FD9\u4E2A GitHub \u4ED3\u5E93\u5F53\u4EE3\u7801\u6E90\uFF08\u9996\u6B21\u53D1\u5E03\u65F6\u81EA\u5EFA\uFF09\uFF0C",
24858
+ "# build \u6BB5\u53EA\u662F\u300C\u89E6\u53D1 \u2192 \u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\u300D\uFF1Bsmoke / deploy \u5404\u81EA\u628A :latest \u89E3\u6790\u6210 digest \u518D\u7528\u3002\u6D41\u6C34\u7EBF\u811A\u672C\u5728 ottin4ttc/clawos \u4ED3\u5E93\u91CC\u3002",
24838
24859
  "#",
24839
- "# \u8981\u7684\u7EC4\u7EC7\u7EA7 Secrets\uFF1AALI_DOCKER_USERNAME / ALI_DOCKER_PASSWORD\uFF08\u63A8 ACR\uFF09\u3001CLAWOS_READ_TOKEN",
24840
- "#\uFF08\u8BFB clawos \u4ED3\u5E93\uFF09\u3001CLAWD_GATEWAY_ADMIN_KEY\uFF1B\u7EC4\u7EC7\u7EA7 Variable\uFF1ACLAWD_GATEWAY_URL\u3002",
24860
+ "# \u8981\u7684\u7EC4\u7EC7\u7EA7 Secrets\uFF1AALI_ACS_ACCESS_KEY_ID / ALI_ACS_ACCESS_KEY_SECRET\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09\u3001",
24861
+ "# ALI_DOCKER_USERNAME / ALI_DOCKER_PASSWORD\uFF08\u89E3\u6790\u955C\u50CF digest\uFF09\u3001CLAWOS_READ_TOKEN\uFF08\u8BFB clawos \u4ED3\u5E93\uFF09\u3001CLAWD_GATEWAY_ADMIN_KEY\uFF1B",
24862
+ "# \u7EC4\u7EC7\u7EA7 Variable\uFF1ACLAWD_GATEWAY_URL\u3002",
24841
24863
  "# \u4ED3\u5E93\u7EA7\u540C\u540D\u914D\u7F6E\u4F1A\u76D6\u8FC7\u7EC4\u7EC7\u7EA7\u2014\u2014\u67D0\u4E2A persona \u8981\u6307\u5230\u53E6\u4E00\u53F0 gateway\uFF0C\u5728\u81EA\u5DF1\u4ED3\u5E93\u91CC\u914D\u5373\u53EF\u3002",
24842
24864
  "",
24843
24865
  "on:",
@@ -24850,9 +24872,9 @@ var L = [
24850
24872
  " group: persona-cloud-${{ github.repository }}",
24851
24873
  "",
24852
24874
  "env:",
24853
- " REGISTRY: registry.cn-hangzhou.aliyuncs.com",
24854
- " VPC_REGISTRY: registry-vpc.cn-hangzhou.aliyuncs.com",
24855
- " IMAGE_NAME: ttc-prod/clawd-persona-cloud",
24875
+ ` REGISTRY: ${ACR_REGISTRY}`,
24876
+ ` VPC_REGISTRY: ${ACR_VPC_REGISTRY}`,
24877
+ ` ACR_NAMESPACE: ${ACR_NAMESPACE}`,
24856
24878
  ` CLAWOS_REPO: ${CLAWOS_REPO}`,
24857
24879
  ` CLAWOS_REF: ${CLAWOS_REF}`,
24858
24880
  "",
@@ -24865,93 +24887,60 @@ var L = [
24865
24887
  // 中文说明归 clawd 的上云页面,这里保持机器好认。
24866
24888
  " name: build",
24867
24889
  " runs-on: ubuntu-latest",
24868
- " timeout-minutes: 30",
24869
- // 没有 outputs:——smoke / deploy 段自己读契约(文件头)。build 段整仓 checkout:构建器要拷整个 persona 目录。
24890
+ // ACR 个人版的构建按账号串行:底座(8 分钟)/ api 在前面排着时要等它们先构完。
24891
+ " timeout-minutes: 40",
24892
+ // 没有 outputs:——smoke / deploy 段自己读契约、自己解析 digest(文件头)。
24870
24893
  " steps:",
24871
- " - name: Checkout persona",
24872
- " uses: actions/checkout@v4",
24873
- " with:",
24874
- " path: persona",
24875
- "",
24876
- " - name: Checkout clawos\uFF08\u6784\u5EFA\u5668 / \u6D41\u6C34\u7EBF\u811A\u672C / \u968F\u884C\u8D44\u4EA7\uFF09",
24877
- " uses: actions/checkout@v4",
24878
- " with:",
24879
- " repository: ${{ env.CLAWOS_REPO }}",
24880
- " ref: ${{ env.CLAWOS_REF }}",
24881
- " token: ${{ secrets.CLAWOS_READ_TOKEN }}",
24882
- " path: clawos",
24883
- "",
24884
- ...PLAN_STEP,
24894
+ ...CONTRACT_STEPS,
24885
24895
  " - name: \u51ED\u636E\u9F50\u4E0D\u9F50\uFF08\u7F3A\u54EA\u51E0\u4E2A\u540D\u5B57\u4E00\u6B21\u5217\u5168\uFF09",
24886
24896
  " env:",
24887
24897
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24888
24898
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24889
24899
  " run: node clawos/cloud-host/pipeline/check-secrets.mjs",
24890
24900
  "",
24891
- " - uses: pnpm/action-setup@v4",
24892
- " if: steps.plan.outputs.asset_builds != ''",
24893
- " with:",
24894
- " version: 10",
24895
- "",
24896
- " - uses: actions/setup-node@v4",
24897
- " if: steps.plan.outputs.asset_builds != ''",
24898
- " with:",
24899
- " node-version: 20",
24900
- " cache: pnpm",
24901
- " cache-dependency-path: clawos/clawd/pnpm-lock.yaml",
24902
- "",
24903
- " - name: \u6784\u968F\u884C\u8D44\u4EA7\uFF08\u6E05\u5355\u91CC\u70B9\u8FC7\u540D\u3001\u4E14\u662F\u4ED3\u5E93\u6784\u5EFA\u4EA7\u7269\u7684\u90A3\u4E9B\uFF09",
24904
- " # \u547D\u4EE4\u6765\u81EA assets.json\uFF0C\u5B83\u81EA\u5DF1\u5E26\u88C5\u4F9D\u8D56\u90A3\u4E00\u6B65\u3002< /dev/null\uFF1A\u522B\u8BA9\u67D0\u6761\u547D\u4EE4\u628A here-string \u91CC\u5269\u4E0B\u7684\u884C\u5F53 stdin \u5403\u6389",
24905
- " if: steps.plan.outputs.asset_builds != ''",
24906
- " working-directory: clawos",
24901
+ " - name: Dockerfile \u5728\u3001\u4E14\u62F7\u5230\u7684\u662F\u8FD9\u4E2A persona \u7684\u76EE\u5F55",
24902
+ " # Dockerfile \u7531 clawd \u53D1\u5E03\u65F6\u5199\uFF08\u540C\u8FD9\u4EFD workflow\uFF09\uFF0CACR \u6309\u5B83\u6784\u3002\u76EE\u5F55\u540D\u90A3\u4E00\u6BB5\u8981\u4E0E deploy-file \u7B97\u51FA\u7684 persona_id \u4E00\u81F4\uFF1A",
24903
+ " # \u4E24\u8FB9\u5404\u6709\u4E00\u4EFD\u540C\u6837\u7684\u540D\u5B57\u6E05\u6D17\uFF0C\u8FD9\u91CC\u662F\u5B83\u4EEC\u552F\u4E00\u7684\u4EA4\u6C47\u70B9\u3002",
24907
24904
  " run: |",
24908
- " set -e",
24909
- " while IFS= read -r cmd; do",
24910
- ' [ -n "$cmd" ] || continue',
24911
- ' echo "$ $cmd"',
24912
- ' bash -c "$cmd" < /dev/null',
24913
- " done <<< '${{ steps.plan.outputs.asset_builds }}'",
24914
- "",
24915
- " - name: Login to ACR",
24916
- " uses: aliyun/acr-login@v1",
24917
- " with:",
24918
- " login-server: ${{ env.REGISTRY }}",
24919
- ' username: "${{ secrets.ALI_DOCKER_USERNAME }}"',
24920
- ' password: "${{ secrets.ALI_DOCKER_PASSWORD }}"',
24905
+ " test -f persona/Dockerfile \\",
24906
+ ' || { echo "\u2717 \u4ED3\u5E93\u91CC\u6CA1\u6709 Dockerfile\uFF1A\u8FD9\u6B21\u63A8\u9001\u4E0D\u662F clawd \u53D1\u5E03\u7684\uFF08\u6216 clawd \u592A\u65E7\uFF09\uFF1B\u56DE clawd \u7684\u4E0A\u4E91\u9875\u9762\u91CD\u65B0\u53D1\u5E03" >&2; exit 1; }',
24907
+ " grep -qF '/clawd/personas/${{ steps.plan.outputs.persona_id }}/' persona/Dockerfile \\",
24908
+ ' || { echo "\u2717 Dockerfile \u62F7\u5230\u7684\u76EE\u5F55\u4E0D\u662F /clawd/personas/${{ steps.plan.outputs.persona_id }}/" >&2; exit 1; }',
24921
24909
  "",
24922
- " - name: \u6784 persona \u5C42",
24923
- " # \u6784\u5EFA\u5668\u6574\u76EE\u5F55\u62F7\uFF0C`.git` \u4E0D\u662F\u4EBA\u683C\uFF0C\u5148\u5220\u3002\u5E95\u5EA7\u7528 :base \u79FB\u52A8 tag\u2014\u2014runner \u6BCF\u6B21\u90FD\u662F\u5E72\u51C0\u673A\u5668\u3001",
24924
- " # \u5FC5\u7136\u62C9\u6700\u65B0\uFF1Bpersona \u5C42\u81EA\u5DF1\u7684 tag \u5E26 commit sha\u3001\u4E0D\u53EF\u53D8\uFF0C\u96C6\u7FA4\u6309\u5B83\u62C9\u6CA1\u6709\u6B67\u4E49\u3002",
24910
+ " - name: \u88C5 aliyun CLI\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09",
24911
+ " env:",
24912
+ " GH_TOKEN: ${{ github.token }}",
24925
24913
  " run: |",
24926
- " rm -rf persona/.git",
24927
- " node clawos/cloud-host/provision/build-image.mjs \\",
24928
- " --manifest persona/.clawd/deploy.json \\",
24929
- ' --from "$REGISTRY/$IMAGE_NAME:base-${{ steps.plan.outputs.engine }}" \\',
24930
- " --persona-dir persona \\",
24931
- // persona 在镜像里落 /clawd/personas/<id>/(与本机同构),id 是 gateway 登记的名字;同 smoke / register 用的那个输出
24932
- " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
24933
- ' --tag "$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
24914
+ " TAGNAME=$(gh release view --repo aliyun/aliyun-cli --json tagName -q .tagName)",
24915
+ // 不用 ${TAGNAME#v} 这种带花括号的展开:这份模板里 `${` 只许出现在 GitHub 表达式里(spec 守着)
24916
+ ' VER=$(printf %s "$TAGNAME" | sed s/^v//)',
24917
+ ' curl -fsSL -o /tmp/aliyun-cli.tgz "https://github.com/aliyun/aliyun-cli/releases/download/$TAGNAME/aliyun-cli-linux-$VER-amd64.tgz"',
24918
+ " sudo tar -xzf /tmp/aliyun-cli.tgz -C /usr/local/bin",
24919
+ " aliyun version",
24934
24920
  "",
24935
- " - name: \u955C\u50CF\u65AD\u8A00\uFF08\u6E05\u5355\u91CC\u8981\u88C5\u7684\u90FD\u5728\u3001bundle \u91CC persona \u5728\uFF09",
24936
- " # /opt/versions.sh \u6BCF\u884C\u90FD\u4EE5 `|| echo` \u6536\u5C3E\u3001\u6C38\u8FDC exit 0\uFF0C\u53EA\u80FD\u9A8C\u8F93\u51FA\uFF1A\u6BB5\u6570\u8981\u7B49\u4E8E\u6E05\u5355 packages \u7684",
24937
- " # \u6761\u6570\uFF0C\u6BCF\u6BB5\u4E0B\u9762\u8981\u6709\u7248\u672C\u53F7\u3002\u955C\u50CF ENTRYPOINT \u662F sh -c\uFF0C\u547D\u4EE4\u8981\u4F5C\u4E3A\u4E00\u4E2A\u5B57\u7B26\u4E32\u4F20\u3002",
24921
+ " - name: \u8BA9 ACR \u4ECE\u672C\u4ED3\u5E93\u6784\uFF08\u9996\u6B21\u53D1\u5E03\u5148\u5EFA ACR \u4ED3\u5E93\u4E0E\u89C4\u5219\uFF1B\u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\uFF09",
24922
+ " # ACR \u6784\u7684\u662F main \u5F53\u524D\u7684 tip\u3001\u4E0D\u662F github.sha\uFF1Atip \u5DF2\u7ECF\u4E0D\u662F\u672C\u6B21 commit \u65F6\u76F4\u63A5\u7EA2\uFF0C\u8BA9\u66F4\u65B0\u7684\u90A3\u6B21 run \u53BB\u6784\u3001\u53BB\u767B\u8BB0\u3002",
24923
+ " # \u81EA\u52A8\u6784\u5EFA\u5173\u7740\uFF1A\u53EA\u6709\u8FD9\u91CC\u89E6\u53D1\u3001webhook \u4E0D\u6784\uFF0C\u300C\u6784 \u2192 \u5192\u70DF \u2192 \u767B\u8BB0\u300D\u624D\u662F\u4E00\u6761\u6709\u5E8F\u7684\u94FE\u3002",
24924
+ " # \u6784\u51FA\u7684\u662F\u54EA\u4E2A commit \u7531 acr.mjs wait \u6309\u6784\u5EFA\u8BB0\u5F55 + \u65E5\u5FD7\u91CC\u7684 commit \u6838\uFF0C\u4E0D\u770B\u955C\u50CF\u7684\u65F6\u95F4\uFF08\u7F13\u5B58\u547D\u4E2D\u65F6\u90A3\u662F\u8001\u7684\uFF09\u3002",
24925
+ " env:",
24926
+ " ALIBABA_CLOUD_ACCESS_KEY_ID: ${{ secrets.ALI_ACS_ACCESS_KEY_ID }}",
24927
+ " ALIBABA_CLOUD_ACCESS_KEY_SECRET: ${{ secrets.ALI_ACS_ACCESS_KEY_SECRET }}",
24938
24928
  " run: |",
24939
- ' IMG="$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
24940
- ` OUT=$(docker run --rm "$IMG" '/opt/versions.sh')`,
24941
- ' echo "$OUT"',
24942
- ` WANT=$(node -e 'const m=JSON.parse(require("fs").readFileSync("persona/.clawd/deploy.json","utf8"));const b=m.manifest??m;console.log((b.packages??b.clis??[]).length)')`,
24943
- ` echo "$OUT" | awk -v want="$WANT" '`,
24944
- ' /^--- / { name=$2; if ((getline v) <= 0) v=""; n++',
24945
- ' if (v !~ /[0-9]+\\.[0-9]+/) { printf " \u2717 %s \u6CA1\u62A5\u51FA\u7248\u672C\u53F7\uFF1A%s\\n", name, v > "/dev/stderr"; bad++ } }',
24946
- ' END { if (n != want) { printf " \u2717 \u955C\u50CF\u91CC\u53EA\u6709 %d \u6BB5\u7248\u672C\u8F93\u51FA\uFF0C\u6E05\u5355\u8981\u88C5 %d \u4E2A\\n", n, want > "/dev/stderr"; bad++ }',
24947
- " exit bad ? 1 : 0 }'",
24948
- ' echo " \u2713 \u6E05\u5355\u91CC\u8981\u88C5\u7684 $WANT \u4E2A\u90FD\u5728\u4E14\u62A5\u5F97\u51FA\u7248\u672C"',
24949
- ` docker run --rm "$IMG" 'test -d /clawd/personas/\${{ steps.plan.outputs.persona_id }}' \\`,
24950
- ' || { echo " \u2717 /clawd/personas/${{ steps.plan.outputs.persona_id }} \u4E0D\u5728" >&2; exit 1; }',
24951
- ' echo " \u2713 persona \u76EE\u5F55\u5728"',
24929
+ // pipefail:ls-remote 那条管道里 cut 永远退 0,没有 pipefail 的话 ls-remote 挂了 TIP 是空串、红在「main 已经推进到 」这句误导人的话上
24930
+ " set -eo pipefail",
24931
+ ' REPO="$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}"',
24932
+ ' node clawos/cloud-host/pipeline/acr.mjs ensure-repo --repo "$REPO" \\',
24933
+ " --source '${{ github.repository }}' --location / --dockerfile Dockerfile --branch main --tag latest \\",
24934
+ " --summary 'clawd persona ${{ github.event.repository.name }}'",
24935
+ " TIP=$(git -C persona ls-remote origin refs/heads/main | cut -f1)",
24936
+ ` [ "$TIP" = '\${{ github.sha }}' ] \\`,
24937
+ ' || { echo "\u2717 main \u5DF2\u7ECF\u63A8\u8FDB\u5230 $TIP\uFF0C\u672C\u6B21 ${{ github.sha }} \u4E0D\u518D\u6784\uFF1B\u7B49\u65B0\u7684\u90A3\u6B21 run" >&2; exit 1; }',
24938
+ ' node clawos/cloud-host/pipeline/acr.mjs trigger --repo "$REPO" --tag latest',
24939
+ ` node clawos/cloud-host/pipeline/acr.mjs wait --repo "$REPO" --tag latest --commit '\${{ github.sha }}' --timeout-sec 1800`,
24952
24940
  "",
24953
- " - name: Push to ACR",
24954
- ' run: docker push "$REGISTRY/$IMAGE_NAME:${{ steps.plan.outputs.tag }}"',
24941
+ ...ACR_LOGIN_STEPS,
24942
+ " - name: \u955C\u50CF = \u672C\u6B21 commit \u6784\u51FA\u7684\u90A3\u4EFD\uFF08digest\uFF1B\u53EA\u6253\u65E5\u5FD7\uFF0Csmoke / deploy \u5404\u81EA\u518D\u89E3\u6790\u4E00\u6B21\uFF09",
24943
+ ` run: node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY"`,
24955
24944
  "",
24956
24945
  " smoke:",
24957
24946
  " name: smoke",
@@ -24960,9 +24949,10 @@ var L = [
24960
24949
  " timeout-minutes: 20",
24961
24950
  " steps:",
24962
24951
  ...CONTRACT_STEPS,
24952
+ ...ACR_LOGIN_STEPS,
24963
24953
  " - name: \u4E34\u65F6\u767B\u8BB0 \u2192 \u8D77\u4E00\u6B21 Pod \u2192 \u64A4\u9500",
24964
24954
  " # \u767B\u8BB0\u6B63\u5F0F\u53EA\u662F\u5F80 gateway \u5199\u4E00\u884C\uFF0Cgateway \u4E0D\u78B0\u955C\u50CF\uFF1B\u96C6\u7FA4\u62C9\u955C\u50CF\u53D1\u751F\u5728\u7B2C\u4E00\u4E2A\u4EFB\u52A1\u5230\u6765\u65F6\u3002",
24965
- " # \u6CA1\u6709\u8FD9\u4E00\u6B65\uFF0C\u6D41\u6C34\u7EBF\u7EFF\u4E86\u53EA\u4EE3\u8868\u300C\u767B\u8BB0\u4E86\u300D\u3002",
24955
+ " # \u6CA1\u6709\u8FD9\u4E00\u6B65\uFF0C\u6D41\u6C34\u7EBF\u7EFF\u4E86\u53EA\u4EE3\u8868\u300C\u767B\u8BB0\u4E86\u300D\u3002\u955C\u50CF\u7528 digest\uFF08\u96C6\u7FA4 Job \u662F IfNotPresent\uFF0C\u79FB\u52A8 tag \u4F1A\u4E00\u76F4\u8DD1\u65E7\u7684\uFF09\u3002",
24966
24956
  // 模型 / 档位 / 连接器 smoke 也要:试跑那次要跟正式那次拿到同一份,否则验的不是将要上线的东西。
24967
24957
  // 名字形状 deploy-file.mjs 已卡死(persona_id [a-z0-9-]、model / effort [A-Za-z0-9._/-](`/` 是 pi 的 provider/id,不是元字符)、size 四档枚举、task_concurrency 正整数、connectors 无单引号
24968
24958
  // 无换行),所以单引号包住直接拼进命令行是安全的。
@@ -24972,8 +24962,10 @@ var L = [
24972
24962
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24973
24963
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24974
24964
  " run: |",
24965
+ " set -e",
24966
+ RESOLVE_LINE,
24975
24967
  " node clawos/cloud-host/pipeline/smoke.mjs \\",
24976
- " --image '${{ steps.plan.outputs.image }}' \\",
24968
+ ' --image "$IMAGE_REF" \\',
24977
24969
  " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
24978
24970
  " --model '${{ steps.plan.outputs.model }}' \\",
24979
24971
  " --effort '${{ steps.plan.outputs.effort }}' \\",
@@ -24991,6 +24983,7 @@ var L = [
24991
24983
  " environment: production",
24992
24984
  " steps:",
24993
24985
  ...CONTRACT_STEPS,
24986
+ ...ACR_LOGIN_STEPS,
24994
24987
  " - name: \u767B\u8BB0\u6B63\u5F0F",
24995
24988
  " env:",
24996
24989
  " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_GATEWAY_URL }}",
@@ -24998,8 +24991,10 @@ var L = [
24998
24991
  " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24999
24992
  " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
25000
24993
  " run: |",
24994
+ " set -e",
24995
+ RESOLVE_LINE,
25001
24996
  " node clawos/cloud-host/pipeline/register.mjs \\",
25002
- " --image '${{ steps.plan.outputs.image }}' \\",
24997
+ ' --image "$IMAGE_REF" \\',
25003
24998
  " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
25004
24999
  " --model '${{ steps.plan.outputs.model }}' \\",
25005
25000
  " --effort '${{ steps.plan.outputs.effort }}' \\",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.568",
3
+ "version": "0.2.569",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",