@clawos-dev/clawd 0.2.618 → 0.2.620

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.
Files changed (34) hide show
  1. package/dist/app-builder-plugin/mcp-server.cjs +9 -16
  2. package/dist/cli.cjs +153 -700
  3. package/dist/cloud-persona-conversations.html +65 -65
  4. package/dist/dispatch/mcp-server.cjs +9 -29
  5. package/dist/persona-defaults/persona-app-builder/.claude/skills/app-builder-projects/scripts/collect-files.mjs +6 -15
  6. package/dist/persona-defaults/persona-app-builder/.claude/skills/app-builder-projects/scripts/list-projects.mjs +1 -2
  7. package/dist/persona-defaults/persona-app-builder/.claude/skills/app-builder-projects/scripts/record-push.mjs +3 -5
  8. package/dist/persona-defaults/persona-app-builder/.claude/skills/app-builder-projects/scripts/render-sql.mjs +4 -6
  9. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/app.module.ts +1 -7
  10. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/main.ts +3 -9
  11. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/polyfill.ts +3 -9
  12. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/server/src/table-name.ts +2 -5
  13. package/dist/persona-defaults/persona-app-builder/extension-kit/examples/nestjs-react/web/src/App.jsx +1 -8
  14. package/dist/persona-defaults/persona-app-builder/mcp/clawd-app-builder/mcp-server.cjs +9 -16
  15. package/dist/persona-defaults/persona-clawd-butler/.claude/skills/clawd-session-import/scripts/link-sessions.mjs +7 -23
  16. package/dist/persona-defaults/persona-clawd-butler/.claude/skills/scan-sessions-suggest-personas/scripts/extract-signals.mjs +6 -14
  17. package/dist/persona-defaults/persona-dataclaw-builder/.claude/skills/app-builder-projects/scripts/collect-files.mjs +6 -15
  18. package/dist/persona-defaults/persona-dataclaw-builder/.claude/skills/app-builder-projects/scripts/list-projects.mjs +1 -2
  19. package/dist/persona-defaults/persona-dataclaw-builder/.claude/skills/app-builder-projects/scripts/record-push.mjs +3 -5
  20. package/dist/persona-defaults/persona-dataclaw-builder/.claude/skills/app-builder-projects/scripts/render-sql.mjs +4 -6
  21. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/app.module.ts +2 -6
  22. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/dataclaw/dataclaw.client.ts +2 -4
  23. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/dataclaw/dataclaw.controller.ts +1 -2
  24. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/main.ts +4 -11
  25. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/server/src/polyfill.ts +1 -5
  26. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/api.js +1 -4
  27. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/components/BarChart.jsx +0 -1
  28. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/components/ResultCards.jsx +0 -1
  29. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/components/ResultTable.jsx +0 -1
  30. package/dist/persona-defaults/persona-dataclaw-builder/extension-kit/examples/nestjs-react/web/src/enums.js +2 -3
  31. package/dist/persona-defaults/persona-dataclaw-builder/mcp/clawd-app-builder/mcp-server.cjs +9 -16
  32. package/dist/share-ui/assets/{guest-CAiFdsmV.js → guest-nVklLeTD.js} +62 -62
  33. package/dist/share-ui/guest.html +1 -1
  34. package/package.json +1 -1
@@ -1,17 +1,10 @@
1
1
  #!/usr/bin/env node
2
- // 把项目目录里该进仓库的文件收成 GitHub MCP `push_files` 要的 `[{ path, content }]`。
3
- //
4
- // 过滤规则 = 项目根 `.gitignore`(模板那份:node_modules/ dist/ .env .publish.log s.yaml s.*.yaml server/bootstrap .s/ …)
5
- // + 永远排掉 `.git` 和 `.clawd-project.json`(插件的记账文件:publish / record-push 都会改它,进了仓库或哈希就会
6
- // 「每推一次都变一次」,而且里面的 deployments / pushedCommit 也不是源码)。**不要**在这里另写一份排除表:publish.sh 渲进项目目录的 s.int.yaml / s.prod.yaml 含 supabase key,
7
- // 它进不进仓库只该由 .gitignore 一处决定。
8
- // 二进制(前 8KB 含 NUL)和超过 512KB 的文件跳过并列进 `skipped`——push_files 只收文本,
9
- // 而且每个字节都要经模型上下文走一遍;agent 看到 skipped 里有该进仓库的东西要自己判断。
10
- //
2
+ // 收集 GitHub MCP push_files 的文本文件;过滤以项目 .gitignore 为准,避免 s.*.yaml 中的 key 被提交。
3
+ // 始终排除 .git 及根 .clawd-project.json,记账变化不属于源码,不能进入推送或树哈希。
4
+ // 二进制(前 8KB 含 NUL)及超过 512KB 的文件列入 skipped,不进哈希;调用方需判断是否另行处理。
11
5
  // 用法:collect-files.mjs --project <项目目录绝对路径>
12
6
  // 输出:{ files: [{ path, content }], skipped: [{ path, reason }], treeHash }
13
- // treeHash = files 按 path 排序后 sha256(path\0content\0…)。record-push.mjs 把它记进元数据,
14
- // publish tool 再跑一次本脚本比对——不一致就是「改了没推」,拒绝发布。skipped 里的文件不进哈希。
7
+ // treeHash 为按 path 排序的 sha256(path\0content\0…);publish 重算后与 record-push 记账比较,拒绝未推的改动。
15
8
  import { createHash } from 'node:crypto'
16
9
  import { readdir, readFile, stat } from 'node:fs/promises'
17
10
  import { join, relative, sep } from 'node:path'
@@ -58,7 +51,6 @@ function ignored(rel, isDir, rules) {
58
51
  const segments = rel.split('/')
59
52
  for (const rule of rules) {
60
53
  if (rule.anchored) {
61
- // 前缀匹配:rel 等于它、或在它下面
62
54
  for (let i = 1; i <= segments.length; i++) {
63
55
  const head = segments.slice(0, i).join('/')
64
56
  if (rule.re.test(head) && (!rule.dirOnly || isDir || i < segments.length)) return true
@@ -67,7 +59,6 @@ function ignored(rel, isDir, rules) {
67
59
  }
68
60
  for (let i = 0; i < segments.length; i++) {
69
61
  if (!rule.re.test(segments[i])) continue
70
- // dirOnly:命中的这一段得是目录——要么它不是最后一段(后面还有东西),要么 rel 本身就是目录
71
62
  if (!rule.dirOnly || i < segments.length - 1 || isDir) return true
72
63
  }
73
64
  }
@@ -78,7 +69,7 @@ let rules = []
78
69
  try {
79
70
  rules = parseGitignore(await readFile(join(root, '.gitignore'), 'utf8'))
80
71
  } catch {
81
- // 没有 .gitignore:只排 .git
72
+ // 无法读取 .gitignore 时仍排除 .git 和根 .clawd-project.json。
82
73
  }
83
74
 
84
75
  const files = []
@@ -109,7 +100,7 @@ async function walk(dir) {
109
100
  }
110
101
 
111
102
  await walk(root)
112
- // 按字节序排,不用 localeCompare:不同机器 locale 不同会让同一棵树排出两种顺序
103
+ // 按字符串序而非 localeCompare 排序,避免不同机器 locale 改变树哈希。
113
104
  files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))
114
105
  const hash = createHash('sha256')
115
106
  for (const f of files) hash.update(f.path).update('\0').update(f.content).update('\0')
@@ -24,8 +24,7 @@ for (const dirName of names) {
24
24
  try {
25
25
  const value = JSON.parse(await readFile(join(projectsRoot, dirName, '.clawd-project.json'), 'utf8'))
26
26
  if (value?.name !== dirName || typeof value.createdAt !== 'string') continue
27
- // 双环境后发布记录在 deployments.{integration,prod};prodUrl 保留作兼容字段 = prod 那份的 url。
28
- // 插件还没读写过的老文件顶层就有 prodUrl,原样带出。
27
+ // prodUrl 兼容字段优先取 deployments.prod.url,缺席时保留 legacy 顶层值。
29
28
  const prodUrl = value.deployments?.prod?.url
30
29
  projects.push({ ...value, ...(prodUrl ? { prodUrl } : {}), projectDir: join(projectsRoot, dirName) })
31
30
  } catch {
@@ -1,9 +1,7 @@
1
1
  #!/usr/bin/env node
2
- // 经 GitHub MCP 建仓 / push 之后记账:把 repoUrl、远端 commit sha、push 那一刻的文件树哈希写进项目的 .clawd-project.json。
3
- // publish tool 对没有本地 git 的项目:重算文件树哈希与 pushedTreeHash 比,不一致拒绝发布;一致就记 pushedCommit
4
- // 当 publishedCommit(「线上 = 仓库里的哪个 commit」)。
5
- //
6
- // 用法:record-push.mjs --project <项目目录绝对路径> --commit <push_files 返回的 object.sha> --tree-hash <collect-files.mjs 输出的 treeHash> [--repo-url <https://github.com/ottin4ttc/...>]
2
+ // GitHub MCP push 后记 repoUrl、pushedCommit 和 pushedTreeHash 到 .clawd-project.json。
3
+ // 无本地 git 的项目发布时重算树哈希;一致才以 pushedCommit 记 publishedCommit。
4
+ // 用法:record-push.mjs --project <项目目录绝对路径> --commit <object.sha> --tree-hash <treeHash> [--repo-url <https://github.com/ottin4ttc/...>]
7
5
  // 输出:写回后的元数据 JSON
8
6
  import { readFile, writeFile } from 'node:fs/promises'
9
7
  import { join } from 'node:path'
@@ -1,9 +1,7 @@
1
1
  #!/usr/bin/env node
2
- // 把项目的 server/db/schema.sql 渲成某个环境的 SQL 打到 stdout:`__TABLE_PREFIX__` → 该环境的表前缀。
3
- // 表结构只有这一份源,integration / prod 各渲一次再喂给 supabase MCP 的 execute_sql——两套表结构
4
- // 不会漂移。前缀口径与 publish.sh / remove-extension.sh 相同:
5
- // integration → <APP_NAME>_<SLUG>_int_ prod → <APP_NAME>_<SLUG>_
6
- // ext.conf 没 SLUG 的老项目退成 <APP_NAME>_int_ / <APP_NAME>_。
2
+ // 渲 server/db/schema.sql 的 __TABLE_PREFIX__ 到 stdout,共用一份 DDL。
3
+ // 前缀与 publish/remove 一致:integration 为 <APP_NAME>_<SLUG>_int_,prod 为 <APP_NAME>_<SLUG>_。
4
+ // legacy 无 SLUG 时分别退为 <APP_NAME>_int_ / <APP_NAME>_。
7
5
  import { readFile } from 'node:fs/promises'
8
6
  import { join } from 'node:path'
9
7
 
@@ -27,7 +25,7 @@ function fail(msg) {
27
25
  process.exit(1)
28
26
  }
29
27
 
30
- /** ext.conf 是 bash 赋值文件;这里只认 `KEY=value` / `KEY="value"` 单行,够 APP_NAME / SLUG 用。 */
28
+ /** 只解析单行 KEY=value 及单/双引号,不执行 ext.conf 的 shell 内容。 */
31
29
  function readConf(text) {
32
30
  const out = {}
33
31
  for (const line of text.split('\n')) {
@@ -1,12 +1,8 @@
1
1
  import { Module } from '@nestjs/common';
2
2
  import { DataclawModule } from './dataclaw/dataclaw.module';
3
3
 
4
- // dataclaw 只读后端 BFF 起手骨架:默认只注册 DataclawModule(schema / performance / ppl /
5
- // consultants / intent 五个只读端点,用建页人提供的 apikey 以 Bearer 调公网 dataclaw service)。
6
- // 业务逻辑由 assistant 按用户需求从零加(添 controller/module 进 imports 即可)。
7
- //
8
- // vite middleware / 静态资源 serve 路径仍由 main.ts 处理(dev mount vite,prod express.static),
9
- // 不需要 ServeStaticModule。
4
+ // 起手注册 DataclawModule 的五个只读端点;apikey 只由后端以 Bearer 发往 dataclaw。
5
+ // 静态资源由 main.ts 托管,无需 ServeStaticModule。
10
6
  @Module({
11
7
  imports: [DataclawModule],
12
8
  })
@@ -1,8 +1,7 @@
1
1
  import { Injectable, HttpException, OnModuleInit } from '@nestjs/common'
2
2
  import { DataclawConfig, loadDataclawConfig } from './dataclaw.config'
3
3
 
4
- // dataclaw 公网 service 用自签证书(文档要求 curl -k)。Node fetch(undici) 默认校验 TLS 会握手失败。
5
- // 本 app 唯一出站目标就是 dataclaw 这一个自签 https,进程级放开 TLS 校验即可(最小改动、零依赖)。
4
+ // dataclaw 服务使用自签证书;这里关闭整个进程的 TLS 证书验证,会影响所有出站 HTTPS。
6
5
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
7
6
 
8
7
  // 端点超时:schema / 固定查询走默认;intent-execute 可能跑 LLM 编排,给 90s。
@@ -50,8 +49,7 @@ export class DataclawClient implements OnModuleInit {
50
49
  throw new HttpException({ ok: false, error: `dataclaw 非 JSON 响应: ${text.slice(0, 200)}` }, 502)
51
50
  }
52
51
  if (!res.ok || json?.ok === false) {
53
- // HTTP 非 2xx → 映射上游状态(5xx 归 502);HTTP 2xx 但应用层 {ok:false} → 502
54
- // (别把 200 当错误码抛——对前端是"成功码带错误体"的矛盾态)。
52
+ // 2xx 的应用层 ok:false 及上游 5xx 统一映射为 502,避免以成功状态返回错误体。
55
53
  const status = res.ok ? 502 : res.status >= 500 ? 502 : res.status || 400
56
54
  throw new HttpException(
57
55
  { ok: false, error: json?.error || `dataclaw ${res.status}`, upstreamStatus: res.status },
@@ -1,8 +1,7 @@
1
1
  import { Body, Controller, Get, Post, Query } from '@nestjs/common'
2
2
  import { DataclawClient } from './dataclaw.client'
3
3
 
4
- // app 自己的只读 BFF。main.ts 已 setGlobalPrefix('api' 或子路径 'preview/<port>/api'),
5
- // 故这里的路径不带 /api。前端只调本 app 的 /api/*,apikey 由后端注入,绝不下发浏览器。
4
+ // main.ts 统一添加 /api 前缀;路由不重复写它。apikey 只在后端,不下发浏览器。
6
5
  @Controller()
7
6
  export class DataclawController {
8
7
  constructor(private readonly dc: DataclawClient) {}
@@ -5,11 +5,8 @@ import { NestExpressApplication } from '@nestjs/platform-express';
5
5
  import { AppModule } from './app.module';
6
6
  import * as path from 'node:path';
7
7
 
8
- // 两种跑法:
9
- // - dev:`cd server && pnpm dev`(nest watch)+ 另开一个终端 `cd web && pnpm dev`(vite 独跑,
10
- // /api 走 web/vite.config.js 的 proxy 转到本进程)
11
- // - prod / FC:nest 直接 serve web 的打包产物(publish.sh 的 BUILD_CMD 把 web/dist 拷进 dist/public)
12
- // FC_SERVER_PORT 是 FC 运行时注入的端口;PORT 给本地调试。
8
+ // dev 由 Vite 独跑并代理 /api;FC 托管拷入 dist/public 的 web 产物。
9
+ // 端口优先 FC_SERVER_PORT,其次本地 PORT。
13
10
  async function bootstrap() {
14
11
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
15
12
 
@@ -18,13 +15,9 @@ async function bootstrap() {
18
15
 
19
16
  app.setGlobalPrefix('api', { exclude: ['/'] });
20
17
 
21
- // 无登录门禁:页面打开即用。数据访问鉴权由后端用 DATACLAW_API_KEY(建页人提供的 apikey)注入,
22
- // 见 dataclaw.client —— key 绝不下发浏览器。
18
+ // 页面无登录门禁,apikey 仅由后端使用。
23
19
 
24
- // 静态资源两条路(覆盖 FC 部署与本地 monorepo 启动两种场景):
25
- // 1. FC(CODE_DIR=./server 只上传 server/,运行时 __dirname=dist/):publish.sh BUILD_CMD 末尾
26
- // 把 ../web/dist 拷进 dist/public,跟着 server 一起上传,所以优先用 __dirname/public
27
- // 2. 本地 `node dist/main.js`:__dirname/public 不存在时 fallback 到 ../../web/dist
20
+ // FC 仅上传 server/,优先托管 dist/public;本地构建可回落到 web/dist。
28
21
  const fs = await import('node:fs');
29
22
  const fcStaticDir = path.resolve(__dirname, 'public');
30
23
  const monorepoStaticDir = path.resolve(__dirname, '..', '..', 'web', 'dist');
@@ -1,6 +1,2 @@
1
- // Dev 模式 .env loader:`nest start --watch` 不会经过 `node --env-file=.env`,
2
- // server 拿不到 DATACLAW_* env → loadDataclawConfig 会 fail-loud。
3
- // 这里在 nest bootstrap 之前显式 require dotenv 把 .env 填进 process.env。
4
- // prod 路径(node --env-file=.env dist/main.js)Node 自带 loader 已经填了,dotenv 看到
5
- // 已存在的 env 不会覆盖(默认行为),行为对齐。
1
+ // nest watch 不经过 Node --env-file;bootstrap 前加载 .env,dotenv 不覆盖已注入的 env。
6
2
  require('dotenv/config');
@@ -1,7 +1,4 @@
1
- // 只调 app 自己的 BFF(/api/*),绝不直连 dataclaw —— apikey 在 server 侧注入,不进浏览器。
2
- //
3
- // dev 隧道模式下页面挂在子路径 /preview/<port>/ 下(见 vite.config.js base),
4
- // 所以 API_BASE 要拼上 import.meta.env.BASE_URL,否则 fetch 会打到错误的绝对路径。
1
+ // 只调本 app 的 BFF,apikey 留在后端;API 路径相对 Vite BASE_URL(默认 /)。
5
2
  const API_BASE = (import.meta.env.BASE_URL || '/').replace(/\/+$/, '') + '/api';
6
3
 
7
4
  async function req(path, opts = {}) {
@@ -1,4 +1,3 @@
1
- // 纯 SVG 横向柱状图,不引第三方依赖。props { rows, labelField, valueField }。
2
1
  export default function BarChart({ rows, labelField, valueField }) {
3
2
  if (!rows || rows.length === 0) return null;
4
3
 
@@ -1,4 +1,3 @@
1
- // 结果卡片。props { rows, titleField, valueField }。数字按 zh-CN 千分位展示。
2
1
  export default function ResultCards({ rows, titleField, valueField }) {
3
2
  if (!rows || rows.length === 0) return <div className="empty">无数据</div>;
4
3
  return (
@@ -1,6 +1,5 @@
1
1
  import { INTERNAL_FIELDS } from '../enums';
2
2
 
3
- // 结果表格。列取 rows[0] 的 key(过滤 _provenance 等内部字段),数字按 zh-CN 千分位展示,空数组显示「无数据」。
4
3
  export default function ResultTable({ rows }) {
5
4
  if (!rows || rows.length === 0) return <div className="empty">无数据</div>;
6
5
  const cols = Object.keys(rows[0]).filter((c) => !INTERNAL_FIELDS.has(c));
@@ -1,7 +1,6 @@
1
- // 内部字段:dataclaw 返回里不展示给用户的列(编号 / ID / 溯源元数据等)。
2
- // ResultTable 渲染时按此 Set 过滤掉对应列。
1
+ // 渲染结果时隐藏内部编号、ID 及溯源元数据。
3
2
  export const INTERNAL_FIELDS = new Set([
4
3
  'ID', 'unique_id', '链接', 'SourceID', '发票ID', '客户ID', '职位ID',
5
4
  '业绩所属一级团队编号', '业绩所属二级团队编号', '业绩所属三级团队编号', '所属OP名称', '候选人ID',
6
- '_provenance', // dataclaw 每条返回都带的溯源元数据(source/record_type/fetched_at/trace_id),不展示
5
+ '_provenance',
7
6
  ]);
@@ -21229,17 +21229,12 @@ var ProjectStore = class {
21229
21229
  await this.write(validated.data);
21230
21230
  return validated.data;
21231
21231
  }
21232
- /**
21233
- * 同步内联 scaffold:spawn `new-extension.sh <name> <模板源> <项目目录>` 等 exit。
21234
- * 必须在 `create()` 之后调(脚本要求目标目录已存在且只含 .clawd-project.json)。
21235
- * 失败抛错;上层(core.createProject)catch 后回滚。
21236
- */
21232
+ /** create 后才 scaffold;目标仅含元数据,失败抛给 core 尝试回滚。 */
21237
21233
  async scaffold(name, templateSrcDir, scaffoldScriptPath, extraEnv) {
21238
21234
  const destDir = this.projectDir(name);
21239
21235
  return await new Promise((resolve, reject) => {
21240
21236
  const child = (0, import_node_child_process.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
21241
- // extraEnv 排在 PATH **之前**:凭据表里若混进一条名叫 PATH 的条目,顶掉 PATH 会让
21242
- // 脚本以「命令找不到」的形态崩在离现场很远的地方。
21237
+ // 恢复宿主 PATH,避免 extraEnv 的同名值破坏脚本命令查找。
21243
21238
  env: { ...process.env, ...extraEnv ?? {}, PATH: process.env.PATH ?? "" },
21244
21239
  stdio: ["ignore", "pipe", "pipe"]
21245
21240
  });
@@ -23018,7 +23013,8 @@ var PersonaFileSchema = external_exports.object({
23018
23013
  size: external_exports.string().optional(),
23019
23014
  /**
23020
23015
  * 云上 task 运行模式下一个 task Pod 同时跑几个 task(design 2026-09-19-cloud-task-mode §3.6),没写按 4。
23021
- * 同 size:只有发布上云的流水线读它(cloud-host/pipeline/deploy-file.mjs 校验正整数、不合格拒发);本机跑不看;没有设置页,作者直接改 persona.json
23016
+ * 只有发布上云的流水线读它(cloud-host/pipeline/deploy-file.mjs 校验正整数、不合格拒发);本机跑不看。
23017
+ * 发布页的资源预估卡通过 persona:update 保存,下次发布生效。
23022
23018
  */
23023
23019
  taskConcurrency: external_exports.number().int().positive().optional(),
23024
23020
  createdAt: external_exports.number(),
@@ -23134,6 +23130,7 @@ var PersonaUpdateArgsSchema = external_exports.object({
23134
23130
  tool: external_exports.string().optional(),
23135
23131
  // 云上任务 Pod 的规格档:只收四档之一(PersonaFile 层是 string,边界在这里收窄)
23136
23132
  size: PersonaSizeSchema.optional(),
23133
+ taskConcurrency: PersonaFileSchema.shape.taskConcurrency,
23137
23134
  personality: external_exports.string().optional(),
23138
23135
  // 人格补充层正文(见 PersonaInfoResponseSchema.personalityLocal)。与 personality 各写
23139
23136
  // 各层、互不影响;'' = 清空补充层。预装 persona 的编辑入口写的就是这个字段。
@@ -25063,13 +25060,11 @@ var L = [
25063
25060
  "",
25064
25061
  "jobs:",
25065
25062
  " build:",
25066
- // name 就是段 key:daemon 按 jobs API 回的 name 认段(那接口不返回 job 的 key)。
25067
- // 中文说明归 clawd 的上云页面,这里保持机器好认。
25063
+ // jobs API 只返 name 不返 key,故 name 必须用段 key。
25068
25064
  " name: build",
25069
25065
  " runs-on: ubuntu-latest",
25070
- // ACR 个人版的构建按账号串行:底座(8 分钟)/ api 在前面排着时要等它们先构完。
25066
+ // ACR 账号内串行构建,需给其他镜像排队留时间。
25071
25067
  " timeout-minutes: 40",
25072
- // 没有 outputs:——smoke / deploy 段自己读契约、自己解析 digest(文件头)。
25073
25068
  " steps:",
25074
25069
  ...CONTRACT_STEPS,
25075
25070
  " - name: \u51ED\u636E\u9F50\u4E0D\u9F50\uFF08\u7F3A\u54EA\u51E0\u4E2A\u540D\u5B57\u4E00\u6B21\u5217\u5168\uFF09",
@@ -25106,7 +25101,7 @@ var L = [
25106
25101
  " ALIBABA_CLOUD_ACCESS_KEY_ID: ${{ secrets.ALI_ACS_ACCESS_KEY_ID }}",
25107
25102
  " ALIBABA_CLOUD_ACCESS_KEY_SECRET: ${{ secrets.ALI_ACS_ACCESS_KEY_SECRET }}",
25108
25103
  " run: |",
25109
- // pipefail:ls-remote 那条管道里 cut 永远退 0,没有 pipefail 的话 ls-remote 挂了 TIP 是空串、红在「main 已经推进到 」这句误导人的话上
25104
+ // pipefail 让 ls-remote 失败正确传播,避免被 cut 的成功状态掩盖。
25110
25105
  " set -eo pipefail",
25111
25106
  ' REPO="$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}"',
25112
25107
  ' node clawos/cloud-host/pipeline/acr.mjs ensure-repo --repo "$REPO" \\',
@@ -25133,9 +25128,7 @@ var L = [
25133
25128
  " - name: \u4E34\u65F6\u767B\u8BB0 \u2192 \u8D77\u4E00\u6B21 Pod \u2192 \u64A4\u9500",
25134
25129
  " # \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",
25135
25130
  " # \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",
25136
- // 模型 / 档位 / 连接器 smoke 也要:试跑那次要跟正式那次拿到同一份,否则验的不是将要上线的东西。
25137
- // 名字形状 deploy-file.mjs 已卡死(persona_id [a-z0-9-]、model / effort [A-Za-z0-9._/-](`/` 是 pi 的 provider/id,不是元字符)、size 四档枚举、task_concurrency 正整数、connectors 无单引号
25138
- // 无换行),所以单引号包住直接拼进命令行是安全的。
25131
+ // smoke 与正式发布用同份模型/档位/连接器;deploy-file.mjs 拒绝单引号/换行等危险值,方可单引号拼参。
25139
25132
  " env:",
25140
25133
  " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_GATEWAY_URL }}",
25141
25134
  " CLAWD_GATEWAY_ADMIN_KEY: ${{ secrets.CLAWD_GATEWAY_ADMIN_KEY }}",