跳转到正文
报告库
用途分类 / 开发辅助

Lark Apps Skill 安全审计

作者说它能做什么(原文)

妙搭(Spark/Miaoda)应用开发与托管:应用创建、本地全栈开发、云端生成迭代、创意设计(UI mockup / 可交互原型 / 线框图 / 落地页 / 仪表盘 / 幻灯片 deck / 视觉探索)、AI相关能力和飞书平台能力或者其他外部能力集成、日志/Trace/监控指标/PV/UV 查询、环境变量管理、应用协作者与协作权限设置、应用角色与成员管理、自动化触发器(定时/记录变更/Webhook/飞书审批)。当用户要开发/新建一个系统·工具·平台·应用,或要本地开发 / 云端开发 / 修改 / 部署 / 发布 / 上线 / 拿可分享链接,或用 HTML 做页面·网站·部署到妙搭,或要设计 / design / mockup / prototype / wireframe / 做 PPT / deck / 视觉探索,或提到妙搭/Spark/Miaoda(应用运行时域名形如 *.aifo

第三方安全检查结论

先别安装或运行

已检查文件
54
发现的风险
11
会不会运行危险命令?检查是否下载程序后直接运行、让他人远程控制电脑,或藏起要运行的命令。发现 4 项风险
高风险

导出的 HTML 可能保留不受信任元素的可执行属性和嵌入内容

原文依据:4 处
发现了什么

克隆逻辑只明确删除注释和 SCRIPT 元素;其他元素通过 cloneNode(false) 复制原有属性,再递归复制子节点。它没有移除 onload/onclick 等事件属性,也没有排除 iframe、object、embed、form 等活动元素,随后把克隆结果直接写入独立 HTML。

为什么需要注意

如果画板包含恶意或被污染的 HTML,用户打开下载文件时可能执行其中的 JavaScript、加载外部页面或提交数据。该代码还可能读取导出页面内的内容并发送到网络。

风险有源码依据,但发生在用户点击“下载 HTML”并随后打开文件时。克隆器只排除注释和 `SCRIPT`,而 `cloneNode(false)` 会保留其他元素的属性;结果未经活动内容过滤便写入独立 HTML。因此,若画板含事件属性、iframe、object 等不受信任内容,导出文件可能保留其行为。用户可要求作者对允许的标签和属性采用白名单,并在隔离环境中打开导出文件。

creative-design/starter-components/design-canvas.jsx:1019来自代码
  const cloneStyled = (src) => {    if (src.nodeType === 8 || (src.nodeType === 1 && src.tagName === 'SCRIPT')) return document.createTextNode('');    const dst = src.cloneNode(false);    if (src.nodeType === 1) {      const cs = getComputedStyle(src); let txt = '';      for (let i = 0; i < cs.length; i++) txt += cs[i] + ':' + cs.getPropertyValue(cs[i]) + ';';      dst.setAttribute('style', txt + 'animation:none;transition:none;');      if (src.tagName === 'CANVAS') try { const im = document.createElement('img'); im.src = src.toDataURL(); im.setAttribute('style', txt); return im; } catch {}    }    for (let c = src.firstChild; c; c = c.nextSibling) dst.appendChild(cloneStyled(c));    return dst;  };
查看另外 3 个位置
creative-design/starter-components/design-canvas.jsx:1053来自代码
  const xml = new XMLSerializer().serializeToString(clone);  const save = (blob, ext) => {    if (!blob) return;    const a = document.createElement('a');    a.href = URL.createObjectURL(blob); a.download = name + '.' + ext; a.click();    setTimeout(() => URL.revokeObjectURL(a.href), 1000);  };  if (kind === 'html') {    const html = '<!doctype html><html><head><meta charset="utf-8"><title>' + name + '</title>' +      (fontCss ? '<style>' + fontCss + '</style>' : '') +      '</head><body style="margin:0">' + xml + '</body></html>';    return save(new Blob([html], { type: 'text/html' }), 'html');  }
creative-design/starter-components/design-canvas.jsx:1061来自代码
  if (kind === 'html') {    const html = '<!doctype html><html><head><meta charset="utf-8"><title>' + name + '</title>' +      (fontCss ? '<style>' + fontCss + '</style>' : '') +      '</head><body style="margin:0">' + xml + '</body></html>';    return save(new Blob([html], { type: 'text/html' }), 'html');  }
creative-design/starter-components/design-canvas.jsx:1206来自代码
            </button>            {menuOpen && (              <div className="dc-menu" onPointerDown={(e) => e.stopPropagation()}>                <button onClick={() => doExport('png')}>下载 PNG</button>                <button onClick={() => doExport('html')}>下载 HTML</button>                <button className="dc-danger"
中风险

运行时才决定要执行什么代码

原文依据:4 处
发现了什么

最终命令来自变量,这次静态检查无法确认实际会运行什么。

为什么需要注意

表面看不出来的内容,可能让电脑执行额外命令。现在还不能确定它实际会做什么。

这段代码的正常用途

这里的 `re.exec` 是正则表达式匹配,用来查找 CSS 中的 `url(...)`,并不是 JavaScript 的 `eval`、动态命令执行或解释器调用。匹配结果随后仅用于解析资源 URL 和替换 CSS 文本。

这项判断针对展示的代码和适用条件,不表示风险已经实际发生。
这段代码的正常用途

这里同样只是用正则表达式的 `exec` 枚举 `background-image` 中的 URL;没有把匹配内容作为代码或命令运行。匹配到的 URL 被交给资源转换函数,并用于更新导出副本的样式。

这项判断针对展示的代码和适用条件,不表示风险已经实际发生。
creative-design/starter-components/design-canvas.jsx:1011来自代码
    let out = rule.css, m; const re = /url\((['"]?)([^'")]+)\1\)/g;    while ((m = re.exec(rule.css))) {      if (m[2].indexOf('data:') === 0) continue;
查看另外 3 个位置
creative-design/starter-components/design-canvas.jsx:1010来自代码
  const fontCss = (await Promise.all(fontRules.map(async (rule) => {    let out = rule.css, m; const re = /url\((['"]?)([^'")]+)\1\)/g;    while ((m = re.exec(rule.css))) {      if (m[2].indexOf('data:') === 0) continue;      let abs; try { abs = new URL(m[2], rule.base).href; } catch { continue; }      out = out.split(m[0]).join('url("' + await toDataURL(abs) + '")');    }
creative-design/starter-components/design-canvas.jsx:1045来自代码
    let m; const re = /url\(["']?([^"')]+)["']?\)/g;    while ((m = re.exec(bg))) {      const tok = m[0], url = m[1];
creative-design/starter-components/design-canvas.jsx:1042来自代码
  });  [clone, ...clone.querySelectorAll('*')].forEach((el) => {    const bg = el.style.backgroundImage; if (!bg) return;    let m; const re = /url\(["']?([^"')]+)["']?\)/g;    while ((m = re.exec(bg))) {      const tok = m[0], url = m[1];      if (url.indexOf('data:') === 0) continue;      jobs.push(toDataURL(url).then((d) => { el.style.backgroundImage = el.style.backgroundImage.split(tok).join('url("' + d + '")'); }));    }  });
中风险

生成的页面会执行远程 CDN JavaScript,且没有完整性校验

原文依据:3 处
发现了什么

起步模板从飞书 CDN 加载 React、ReactDOM 和浏览器内 Babel。版本虽固定,但 script 标签没有 `integrity` 校验或本地副本;页面每次加载都信任 CDN 返回的可执行代码。

为什么需要注意

如果 CDN、分发路径或上游发布过程被攻破,替换后的脚本可在应用页面权限下读取页面内容、监听输入并发起网络请求。页面无法通过浏览器完整性检查发现代码被替换。

起步模板加载三个远程可执行脚本。版本号已固定,降低了意外升级风险,但标签没有 `integrity` 属性;因此页面加载时仍信任该 CDN 和传输结果。若 CDN、发布路径或上游账户被攻破,返回脚本可在页面权限下读取或修改页面数据。用户可要求自托管审核过的副本、添加可验证的 SRI(若 CDN 支持稳定内容),并用 CSP 限制脚本来源。

creative-design/assets/index.html:9来自说明文档
  <script>window.gfdatav1={"env":"prod","envName":"prod","runtime":"node","ver":"1.0.0.126","canary":0,"idc":"hl","region":"CN","vdc":"hl","vregion":"China-North","extra":{"canaryType":null}}</script><script    src="https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk/react@18.3.1/umd/react.development.js"    crossorigin="anonymous"></script>  <script    src="https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk/react-dom@18.3.1/umd/react-dom.development.js"    crossorigin="anonymous"></script>  <script    src="https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk/@babel/standalone@7.29.0/babel.min.js"    crossorigin="anonymous"></script>  <!-- 其他内容 -->
查看另外 2 个位置
creative-design/assets/index.html:8来自说明文档
  <title></title>  <script>window.gfdatav1={"env":"prod","envName":"prod","runtime":"node","ver":"1.0.0.126","canary":0,"idc":"hl","region":"CN","vdc":"hl","vregion":"China-North","extra":{"canaryType":null}}</script><script    src="https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk/react@18.3.1/umd/react.development.js"    crossorigin="anonymous"></script>  <script    src="https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk/react-dom@18.3.1/umd/react-dom.development.js"    crossorigin="anonymous"></script>  <script    src="https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk/@babel/standalone@7.29.0/babel.min.js"    crossorigin="anonymous"></script>  <!-- 其他内容 -->
creative-design/creative-design.md:136来自说明文档
## React + Babel(浏览器内 JSX)当用浏览器内 JSX 编写 React 原型(无构建步骤——Babel 在运行时转译)时,你必须使用下面这些锁定版本的确切 script 标签。不要使用未锁定版本(例如 react@18)。要用 React + Babel 时,可直接从本 skill 的 `assets/index.html` 拷贝 HTML 模板起步(`cp <本 skill 所在目录>/assets/index.html <任务目录>/index.html`)——它已带好这三个 script 标签和 `#root` 挂载点,不必手写。```html<script src="https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk/react@18.3.1/umd/react.development.js" crossorigin="anonymous"></script><script src="https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk/react-dom@18.3.1/umd/react-dom.development.js" crossorigin="anonymous"></script><script src="https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk/@babel/standalone@7.29.0/babel.min.js" crossorigin="anonymous"></script>```
中风险

本地开发和插件流程允许安装未固定的最新依赖

原文依据:4 处
发现了什么

本地流程直接运行 `npm install`,插件安装在未提供版本时选择最新版。安装过程会从包源取得代码,并可能执行包声明的安装脚本;“最新版”也会随时间变化,不能保证与审核时相同。

为什么需要注意

被攻破、恶意或后来发生变化的依赖可能在开发机器上执行代码,读取当前项目可访问的文件或修改构建产物。结果也难以复现和审计。

这段证据能说明什么

插件命令明确规定省略 `--version` 就安装最新版,因此该部分确有随时间变化的供应链风险;用户可要求始终指定并审核版本。另一方面,`npm install` 是否未固定取决于未提供的 `package.json` 和锁文件,现有行也没有说明会执行安装脚本,所以无法从证据确认候选对 npm 的完整描述。安装插件本身符合“接入插件能力”的声明用途,但仍应仅在用户要求该能力时进行。

这项判断针对展示的代码和适用条件,不表示风险已经实际发生。
references/lark-apps-local-dev.md:26来自说明文档
# 进入仓库后按项目脚手架启动cd ./approval-appnpm installnpm run dev
查看另外 3 个位置
references/lark-apps-plugin-install.md:15来自说明文档
- `--name <key>`:插件包 key(从仓库 Skill 的「AI 插件目录」获取)。不传则批量安装 `actionPlugins` 中声明的所有插件。- `--version <ver>`:指定版本(如 `1.0.0`)。不传则安装最新版。
references/lark-apps-plugin-install.md:22来自说明文档
```bash# 安装最新版lark-cli apps +plugin-install --name <plugin-key># 安装指定版本lark-cli apps +plugin-install --name <plugin-key> --version 1.0.0# 批量安装已声明的所有插件lark-cli apps +plugin-install```
references/lark-apps-plugin-install.md:9来自说明文档
用户要接入 AI 能力或飞书平台能力,需要先安装对应的插件包。安装后才能创建插件实例。具体有哪些可用插件、该选哪个,读取创建的应用仓库 Skill:`.agents/skills/plugin-guide/SKILL.md`。**插件包 ≠ npm 包**:插件包写入 `actionPlugins`,npm 写入 `dependencies`,两套独立机制。禁止用 `npm install` 代替本命令。
会不会泄露文件和密钥?检查是否发送含密码或密钥的文件,以及代码里是否直接写了密钥。发现 3 项风险
中风险

普通设计请求可能被自动上传并发布到妙搭云端

原文依据:6 处
发现了什么

创意工作流把创建应用、初始化远端仓库、提交、推送和发布列为默认步骤,没有把“仅生成本地文件”和“授权上传发布”明确分开。另一份旧发布说明却要求仅在用户明确要求部署或分享时发布,形成授权边界冲突。

为什么需要注意

设计内容、附件衍生内容和源码会离开本地环境,写入用户的妙搭账户和远端 Git 仓库,并生成线上版本。链接默认可能受限,但云端副本和账户资产仍已创建;以后放宽可见范围时内容可能被更多人看到。

创意设计的触发范围包括普通 mockup、原型和 deck,而其活动工作流要求每个新任务创建云端应用和仓库,随后提交、推送并发布以取得链接。这里没有在发布前单独检查用户是否授权外传,因此仅想要本地设计的用户也可能把文件和内容上传到妙搭。用户可要求作者把“仅本地交付”设为默认,并让创建应用、push 和 release 各自以明确发布意图为前提。旧版 `html-publish` 的限制不覆盖这条新建创意模式链路。

creative-design/creative-design.md:18来自说明文档
3. 列出 todo 清单。4. 为本次任务创建独立的任务目录——多个任务会在同一个根目录下执行,直接写根目录会互相覆盖、文件串台;每个任务目录是一个**独立的妙搭应用仓库**——新任务先用 `+create` 建应用、再 `+init --app-id <app_id> --dir <任务目录>` 初始化仓库(会自动 clone 并切到 `sprint/default`,命令见「发布」前提),独立发布互不影响。把资源复制进任务目录,在其中创建交付物。用图片素材提升美观度与丰富度、或需要有依据的内容时,按「图像素材与外部信息」补充。5. (如有)自检React + Babel路径是否正确;ReactDOM.createRoot 是否参数正确,对应元素是否存在6. 收尾:提交你的改动。7. 发布:把产物发布到妙搭拿到可访问链接(见下方「发布」)。写完不发布,用户拿不到线上链接。8. 极其简短地总结——只讲注意事项与后续步骤,并给出发布后的可访问链接。
查看另外 5 个位置
creative-design/creative-design.md:208来自说明文档
```bash# 1. 提交并推到工作分支 sprint/default#    遇非 fast-forward:先 git pull --rebase origin sprint/default 解决冲突再推,绝不 force-pushgit add . && git commit -m "feat: ..." && git push origin sprint/default# 2. 发起部署(记下返回的 release_id),然后轮询状态直到 finished / failed:#    publishing → 继续轮询;finished → 输出含可分享的 online_url,直接返回给用户;failed → 按输出中的 error_logs 报告失败原因lark-cli apps +release-create --app-id <app_id> --as userlark-cli apps +release-get --app-id <app_id> --release-id <release_id> --as user```
references/lark-apps-html-publish.md:43来自说明文档
## 预览与发布边界- 用户只说“用 HTML 写个 PPT/页面给我看看”时,先生成本地文件或目录,返回路径并问是否发布到妙搭分享;不要默认创建应用或部署。- 用户明确说“部署出去/发链接/可分享”时,才创建 `html` 应用并用 `+html-publish`。- 用户要发布但没有 app_id 时,先 `+create --app-type html` 创建应用;应用名可从页面/站点主题生成,不要让用户手动提供 app_id。- 若产物首页不是 `index.html`,发布前改名或复制为 `index.html`;目录发布时只传干净产物目录,例如 `./dist`。`.git` 目录会被自动排除,不会进入压缩包。
creative-design/creative-design.md:3来自说明文档
name: creative-designdescription: 以自包含 HTML 创建精致的设计产物:UI mockup、可交互原型、线框图(wireframe)、落地页、仪表盘、应用屏幕、移动 App、幻灯片 deck(即 PPT / PowerPoint 演示文稿)、动画视频(motion graphics、产品演示 Demo 动画、数据动画)、可视化报告 / 信息图(infographic)/ 视觉长图与视觉探索。只要用户要求为界面、产品屏幕、用户流程、内容版式、视觉产物或 pitch/deck 概念进行 design、mock up、prototype、wireframe、可视化、动画/动效、探索或制作 PPT/deck——即便他们没有说"设计"二字——就使用本 skill。Harness 无关:适用于 Aily、Claude Code、Codex Agent 及类似的具备文件能力的 agent。---
creative-design/creative-design.md:187来自说明文档
## 发布设计产物写完并提交后,需要发布到妙搭(lark-apps)才能拿到可访问链接。本 skill 产出的是创意模式(html)应用,发布走本地开发链路:改动 git commit 后推到工作分支 `sprint/default`,再用 `lark-cli apps` 命令发起部署并轮询结果。
SKILL.md:36来自说明文档
| HTML 应用 / 创意模式 — 写 HTML 页面/网站、静态页、PPT/deck、落地页、仪表盘、UI mockup、原型、线框图、视觉探索 | 加载 [`creative-design/creative-design.md`](creative-design/creative-design.md)(含完整开发与发布流程) | [`creative-design/creative-design.md`](creative-design/creative-design.md) || 旧版存量 HTML 应用(无 Git 管理)继续上传已有静态产物 | `+html-publish`(仅兼容旧链路;新建 html / 创意模式 / creative-design 产物不得使用) | [`lark-apps-html-publish.md`](references/lark-apps-html-publish.md) || 开发已有应用 / 初始化本地仓库(开发方式已定为本地后;先解析 app_id,勿 `+create` 新建) | `+init`(或手动 `+git-credential-init` + 原生 git)。**执行前必读** [`lark-apps-local-dev.md`](references/lark-apps-local-dev.md),含端到端流程和领域规则 | [`lark-apps-init.md`](references/lark-apps-init.md), [`lark-apps-git-credential.md`](references/lark-apps-git-credential.md) |
中风险

Deck 组件会把完整 HTML 和演示备注发送给任意来源的父页面

原文依据:4 处
发现了什么

组件使用目标来源 `'*'` 的 `window.parent.postMessage` 发送完整 `outerHTML` 和备注,没有把接收者限制为受信任的妙搭域名。Design Canvas 的文件写入消息也采用相同的通配目标。

为什么需要注意

若已发布页面被恶意或不受信任的网站嵌入,用户执行删除、移动、隐藏或备注编辑等操作时,父页面可收到演示内容和备注。材料中的内部计划、客户信息或未公开数据可能泄露给嵌入站点。

当用户编辑备注或重排、删除幻灯片时,组件会把备注数组或完整 `outerHTML` 通过 `postMessage(..., '*')` 发给父窗口;Design Canvas 也把文件路径和内容以通配目标发送。若页面被非妙搭站点嵌入,该父页面可能收到设计内容和备注。源码没有证明部署层会阻止第三方嵌入。用户可要求限定可信 origin、验证宿主握手,并通过 CSP `frame-ancestors` 限制嵌入者。

creative-design/starter-components/deck-stage.js:1297来自代码
    /** Persist a pure text edit: mirror the in-DOM #speaker-notes tag (if any)     *  for in-iframe consumers, and post the full array to the parent so the     *  host writes it to disk — the tag lives OUTSIDE <deck-stage>, so the     *  deck-changed outerHTML path can't carry notes. */    _emitNotesChange() {      const notes = this._notesForEmit();      this._notes = notes;      const tag = document.getElementById('speaker-notes');      if (tag) tag.textContent = JSON.stringify(notes);      this.dispatchEvent(new CustomEvent('noteschange', {        detail: { notes, index: this._index }, bubbles: true, composed: true,      }));      try { window.parent.postMessage({ type: 'miaoda:deck:notes-changed', index: this._index, notes }, '*'); } catch (e) {}    }
查看另外 3 个位置
creative-design/starter-components/deck-stage.js:2393来自代码
      }));      // Forward to parent so the host can persist mutations (the CustomEvent      // cannot cross iframe boundaries). detail.slide is an Element and can't      // survive structured-clone, so only the scalars cross.      try {        window.parent.postMessage({          type: 'miaoda:deck:deck-changed',          action: detail.action, from: detail.from, to: detail.to,          html: this.outerHTML,          notes: this._notesForEmit(),        }, '*');      } catch (e) {}    }
creative-design/starter-components/design-canvas.jsx:225来自代码
// Persist a sidecar file back to the host.function miaodaWriteFile(path, content) {  try {    window.parent.postMessage({ type: 'miaoda:bridge:write-file', path: path, content: content }, '*');  } catch (e) {    /* no parent — ignore */  }
creative-design/starter-components/design-canvas.jsx:223来自代码
// ─────────────────────────────────────────────────────────────const DC_STATE_FILE = '.design-canvas.state.json';// Persist a sidecar file back to the host.function miaodaWriteFile(path, content) {  try {    window.parent.postMessage({ type: 'miaoda:bridge:write-file', path: path, content: content }, '*');  } catch (e) {    /* no parent — ignore */  }  return Promise.resolve();}
中风险

导出会自动请求画板和样式表引用的 URL,并把成功响应装入文件

原文依据:4 处
发现了什么

导出流程会 fetch 样式表及其递归 @import、字体、图片和背景 URL。请求没有来源白名单,也没有显式设置 credentials: 'omit';成功读取的响应会转成 data URI,失败时则保留原 URL。

为什么需要注意

恶意或意外的资源 URL 可在导出时触发网络访问。可读取的响应(包括浏览器允许读取的同源资源)可能被打包进下载文件;未能内联的远程 URL 还可能在以后打开导出 HTML 时继续联系外部服务器。

导出由用户点击触发,联网内联资源也符合“自包含导出”的功能目的;但实现确实会请求画板或样式表提供的 URL,并递归处理 `@import`,没有可见的协议或主机白名单。若设计内容不可信,导出可导致浏览器访问其指定地址;同源请求还可能按浏览器默认规则携带凭据,成功响应会进入导出文件。用户可要求限制协议/域名、显式禁用凭据,并在导出前显示资源清单。

creative-design/starter-components/design-canvas.jsx:977来自代码
  try { await document.fonts.ready; } catch {}  const toDataURL = (url) => fetch(url).then((r) => r.blob()).then((b) => new Promise((res) => {    const fr = new FileReader(); fr.onload = () => res(fr.result); fr.onerror = () => res(url); fr.readAsDataURL(b);  })).catch(() => url);
查看另外 3 个位置
creative-design/starter-components/design-canvas.jsx:987来自代码
  const fontRules = [], pending = [], seen = new Set();  const scrapeCss = (href) => {    if (seen.has(href)) return; seen.add(href);    pending.push(fetch(href).then((r) => r.text()).then((css) => {      for (const m of css.match(/@font-face\s*{[^}]*}/g) || []) fontRules.push({ css: m, base: href });      for (const m of css.matchAll(/@import\s+(?:url\()?['"]?([^'")\s;]+)/g))        scrapeCss(new URL(m[1], href).href);    }).catch(() => {}));  };  const walk = (rules, base) => {    for (const r of rules) {      if (r.type === CSSRule.FONT_FACE_RULE) fontRules.push({ css: r.cssText, base });      else if (r.type === CSSRule.IMPORT_RULE && r.styleSheet) {        const ibase = r.styleSheet.href || base;        try { walk(r.styleSheet.cssRules, ibase); } catch { scrapeCss(ibase); }      } else if (r.cssRules) walk(r.cssRules, base);    }  };  for (const ss of document.styleSheets) {    const base = ss.href || location.href;    try { walk(ss.cssRules, base); } catch { if (ss.href) scrapeCss(ss.href); }  }  while (pending.length) await pending.shift();  const fontCss = (await Promise.all(fontRules.map(async (rule) => {
creative-design/starter-components/design-canvas.jsx:1037来自代码
  const jobs = [];  clone.querySelectorAll('img').forEach((el) => {    const s = el.getAttribute('src');    if (s && s.indexOf('data:') !== 0) jobs.push(toDataURL(el.src).then((d) => el.setAttribute('src', d)));  });  [clone, ...clone.querySelectorAll('*')].forEach((el) => {    const bg = el.style.backgroundImage; if (!bg) return;    let m; const re = /url\(["']?([^"')]+)["']?\)/g;    while ((m = re.exec(bg))) {      const tok = m[0], url = m[1];      if (url.indexOf('data:') === 0) continue;      jobs.push(toDataURL(url).then((d) => { el.style.backgroundImage = el.style.backgroundImage.split(tok).join('url("' + d + '")'); }));    }  });  await Promise.all(jobs);
creative-design/starter-components/design-canvas.jsx:1111来自代码
  const doExport = (kind) => {    setMenuOpen(false);    if (!cardRef.current) return;    // Unicode-aware sanitize: keep letters (incl. CJK/accented), digits,    // whitespace, dot/underscore/hyphen; collapse everything else to '_'.    // ASCII-only \w would strip Chinese labels down to a bare '_'.    const name = String(label || id || 'artboard').replace(/[^\p{L}\p{N}\s._-]+/gu, '_');    const ew = cardRef.current.offsetWidth || width;    const eh = cardRef.current.offsetHeight || height;    dcExport(cardRef.current, ew, eh, name, kind)      .catch((e) => console.error('[design-canvas] export failed:', e));  };
会不会删除文件或一直在后台运行?检查是否大范围删除文件、改写磁盘,或设置自动启动。未发现风险
会不会绕过安全保护?检查是否跳过网站安全验证、开放过多文件权限,或取消操作前的确认。发现 3 项风险
高风险

默认建表模板允许所有已登录用户修改全部数据,并允许匿名读取全部数据

原文依据:4 处
发现了什么

平台 SQL 模板创建了 `FOR ALL TO authenticated USING (true)` 策略,同时为 `authenticated, anon` 创建 `SELECT USING (true)` 策略。这不是按用户或角色隔离的数据权限。旁边名为“修改本人数据”的策略并不能收紧更宽的全量允许策略。

为什么需要注意

使用此模板建成的业务表可能让任意已登录应用用户读取和修改所有行,并让未登录访问者读取所有行。订单、审批、人员资料或其他业务数据可能被越权查看或篡改。

推荐的建表模板启用 RLS 后,又授予所有 `authenticated` 身份对表执行全部操作,并允许 `authenticated` 和 `anon` 读取全部行。PostgreSQL 的宽松策略会按 OR 合并,因此后面的“修改本人数据”策略不会收窄这两个全量允许策略。若应用存储私密或分用户数据,这可能导致越权读取或修改。用户可要求作者提供默认拒绝、按所有者或业务角色限制的策略,并在上线前验证匿名和普通登录用户权限。

references/lark-apps-db-execute.md:67来自说明文档
新建业务表必须:4 个审计列 + 启用 RLS + 4 条默认 policy,**放在同一次 `+db-execute` 调用里**(RLS / policy / COMMENT / INDEX 一起)。裸表名,不写 `public.` 或 schema 前缀。
查看另外 3 个位置
references/lark-apps-db-execute.md:95来自说明文档
CREATE POLICY "修改全部数据" ON <table>  AS PERMISSIVE FOR ALL TO authenticated USING (true);CREATE POLICY "查看全部数据" ON <table>  AS PERMISSIVE FOR SELECT TO authenticated, anon USING (true);CREATE POLICY "修改本人数据" ON <table>  AS PERMISSIVE FOR ALL TO authenticated USING (    (current_setting('app.user_id'::text) = ANY (ARRAY[]::text[]))    AND (current_setting('app.user_id'::text) = ((_created_by).user_id)::text)  );```
references/lark-apps-db-execute.md:90来自说明文档
ALTER TABLE <table> ENABLE ROW LEVEL SECURITY;CREATE POLICY service_role_bypass_policy ON <table>  TO service_role USING (true);CREATE POLICY "修改全部数据" ON <table>  AS PERMISSIVE FOR ALL TO authenticated USING (true);CREATE POLICY "查看全部数据" ON <table>  AS PERMISSIVE FOR SELECT TO authenticated, anon USING (true);
references/lark-apps-db-execute.md:101来自说明文档
CREATE POLICY "修改本人数据" ON <table>  AS PERMISSIVE FOR ALL TO authenticated USING (    (current_setting('app.user_id'::text) = ANY (ARRAY[]::text[]))    AND (current_setting('app.user_id'::text) = ((_created_by).user_id)::text)  );```
中风险

Deck 接受任意来源窗口发送的控制消息

原文依据:3 处
发现了什么

组件注册全局 `message` 监听器,但 `_onMessage` 没有检查 `e.origin` 或 `e.source`,便接受展示模式、预览模式、缩略图栏状态和跳页命令。

为什么需要注意

嵌入该页面的不受信任父页面可以改变演示状态、隐藏编辑界面或跳转页面,干扰用户对当前内容和操作状态的判断。与通配符数据发送结合时,父页面还能诱导用户在受其控制的界面状态下操作。

组件在窗口级监听所有 `message` 事件,而处理函数只检查消息字段,没有检查 `e.origin` 或 `e.source`。在页面可被第三方窗口嵌入或持有其窗口引用时,外部发送者可切换演示/预览状态、隐藏缩略图栏或调用跳页。影响主要是界面和用户决策被操纵,所示代码未直接证明文件或账户权限会因此改变。用户可要求只接受已验证妙搭宿主来源及预期父窗口的消息。

creative-design/starter-components/deck-stage.js:715来自代码
      this._syncPrintPageRule();      window.addEventListener('keydown', this._onKey);      window.addEventListener('resize', this._onResize);      window.addEventListener('message', this._onMessage);      window.addEventListener('hashchange', this._onHashChange);      window.addEventListener('click', this._onDocClick, true);      this.addEventListener('click', this._onTap);
查看另外 2 个位置
creative-design/starter-components/deck-stage.js:1694来自代码
    _onMessage(e) {      const d = e.data;      if (d && d.type === 'miaoda:deck:presenting' && typeof d.on === 'boolean') {        this._presenting = d.on;        this._syncMobileMode();        if (!d.on) this._toggleMobUi(false);        this._syncRailHidden();        this._syncNotesHidden();        this._closeMenu();        this._fit();        this._scaleThumbs();      }      // Host's Preview segment (ViewerMode='none'): the rail's drag-reorder /
creative-design/starter-components/deck-stage.js:1724来自代码
      // doesn't change rail visibility. Persists alongside rail width.      if (d && d.type === 'miaoda:deck:rail-visible' && typeof d.on === 'boolean') {        if (d.on === this._railVisible) return;        this._railVisible = d.on;        try { localStorage.setItem('deck-stage.railVisible', d.on ? '1' : '0'); } catch (e) {}        // Notify the parent so its toolbar state stays in sync.        try { window.parent.postMessage({ type: 'miaoda:deck:rail-visible-changed', on: d.on }, '*'); } catch (e) {}        // Arm the transition, commit it, then flip state — otherwise the        // browser coalesces both writes and nothing animates on show.        this.setAttribute('data-rail-anim', '');        void (this._rail && this._rail.offsetHeight);        this._syncRailHidden();        this._fit();        this._scaleThumbs();        clearTimeout(this._railAnimTimer);        this._railAnimTimer = setTimeout(() => this.removeAttribute('data-rail-anim'), 220);      }      if (d && d.type === 'miaoda:deck:rail-enabled') this._enableRail();      if (d && d.type === 'miaoda:deck:goto' && typeof d.index === 'number') this._go(d.index | 0, 'api');    }
中风险

画布和调整面板接受未校验来源的跨窗口控制消息

原文依据:4 处
发现了什么

两个 message 监听器只检查消息数据的 type,没有验证 e.origin 或 e.source。任何能够取得该窗口引用的页面都可发送缩放、探测、面板启用或停用消息。

为什么需要注意

在应用被非预期页面嵌入或窗口引用泄露时,外部页面可以改变画布比例、反复触发宿主通信或隐藏/显示调整面板。这可能干扰操作,并让用户在错误的视觉状态下审核设计;所示入站消息本身不会直接写入 tweak 值。

两个活动的 `message` 监听器只检查消息类型和值,没有检查 `e.origin` 或 `e.source`。因此,能取得该窗口引用的其他窗口可改变缩放或显示/隐藏调整面板;画布的 `probe` 还会触发向父窗口回发状态。当前可见影响主要是界面控制和状态消息,并非凭据窃取。用户可要求仅接受预期父窗口及明确来源的消息。

creative-design/starter-components/design-canvas.jsx:807来自代码
    // Host-driven zoom (toolbar % menu). Zooms around viewport centre so the    // visible midpoint stays fixed — matching the host's iframe-zoom feel.    const onHostMsg = (e) => {      const d = e.data;      if (d && d.type === 'miaoda:canvas:set-zoom' && typeof d.scale === 'number') {        const r = vp.getBoundingClientRect();        zoomAt(r.left + r.width / 2, r.top + r.height / 2, d.scale / tf.current.scale);      } else if (d && d.type === 'miaoda:canvas:probe') {        // Host's [readyGen] reset asks whether a canvas is present; it        // fires on the iframe's native 'load', which for canvases with        // images/fonts is after our mount-time announce, so re-announce.        // Clear the pan-tick guard so apply() re-posts the current scale        // even if it's unchanged — the host just reset dcScale to 1.        window.parent.postMessage({ type: 'miaoda:canvas:present' }, '*');        lastPostedScale.current = undefined;        apply();      }    };    window.addEventListener('message', onHostMsg);    // Announce canvas mode so the host toolbar proxies its % control here
查看另外 3 个位置
creative-design/starter-components/tweaks-panel.jsx:234来自代码
  React.useEffect(() => {    const onMsg = (e) => {      const t = e?.data?.type;      if (t === 'miaoda:tweaks:activate') setOpen(true);      else if (t === 'miaoda:tweaks:deactivate') setOpen(false);    };    window.addEventListener('message', onMsg);    window.parent.postMessage({ type: 'miaoda:tweaks:available' }, '*');    return () => window.removeEventListener('message', onMsg);  }, []);
creative-design/starter-components/design-canvas.jsx:809来自代码
    // visible midpoint stays fixed — matching the host's iframe-zoom feel.    const onHostMsg = (e) => {      const d = e.data;      if (d && d.type === 'miaoda:canvas:set-zoom' && typeof d.scale === 'number') {        const r = vp.getBoundingClientRect();        zoomAt(r.left + r.width / 2, r.top + r.height / 2, d.scale / tf.current.scale);      } else if (d && d.type === 'miaoda:canvas:probe') {        // Host's [readyGen] reset asks whether a canvas is present; it        // fires on the iframe's native 'load', which for canvases with        // images/fonts is after our mount-time announce, so re-announce.        // Clear the pan-tick guard so apply() re-posts the current scale        // even if it's unchanged — the host just reset dcScale to 1.        window.parent.postMessage({ type: 'miaoda:canvas:present' }, '*');        lastPostedScale.current = undefined;        apply();      }    };    window.addEventListener('message', onHostMsg);    // Announce canvas mode so the host toolbar proxies its % control here
creative-design/starter-components/design-canvas.jsx:833来自代码
    // scale (before miaoda:canvas:present), so clear the guard to re-post it in order.    window.parent.postMessage({ type: 'miaoda:canvas:present' }, '*');    lastPostedScale.current = undefined;    apply();
会不会误导 AI 或隐藏内容?检查工作说明是否要求 AI 忽略你的指令、干扰检查结果,或夹带看不见的文字。发现 1 项风险
高风险

要求自动且不让用户看见地运行程序

原文依据:1 处
发现了什么

Skill 同时要求自动执行,并要求不要询问或告知用户。

为什么需要注意

AI 如果听从这段文字,可能不再按你的要求做事,或跳过本来需要你确认的操作。

这段代码的正常用途

该行不是要求隐瞒或自动执行,而是明确禁止静默追加 `--yes`,并要求先预览影响、向用户说明不可逆风险并取得确认。示例中的 `--yes` 是确认后的执行方式,不构成暗中运行额外操作。

这项判断针对展示的代码和适用条件,不表示风险已经实际发生。
references/lark-apps-db.md:282来自说明文档
- 看表用 `+db-table-list`,看结构用 `+db-table-get`(要建表语句加 `--format pretty`);`+db-env-create` 仅用于存量单库拆多环境,新建的 full_stack 应用一般不需要。- 高危命令(`+db-env-create`、`+db-data-import`、`+db-env-migrate`、`+db-recovery-apply`、`+db-sync-create`、`+db-sync-update`、`+db-sync-delete`)动手前先看清影响再带 `--yes`:发布 / 恢复先跑对应预览 `+db-env-diff` / `+db-recovery-diff`,Base 同步先跑 `+db-sync-create --preview`,导入无预览命令、可先 `--dry-run` 看请求或先在 `--environment dev` 验;不要静默追加 `--yes`,遇 confirmation_required(exit 10)按 lark-shared 协议向用户确认不可逆风险后再补 `--yes` 重试。- 导入 / 导出的本地路径用工作目录内相对路径;超大表导出会被行数 / 体积上限拒,改用 `+db-execute` 分批。
会不会偷偷改推广链接或收款方?检查是否强制替换推广链接或收款对象,同时要求隐瞒更改。未发现风险

Skill 逻辑拆解

8 个说明模块

该 Skill 以用户身份管理妙搭资产,范围包括应用、源码仓库、数据库、文件、密钥、成员、权限和自动化;它不是仅生成本地设计文件的工具。

查看原文
SKILL.md:13来自说明文档
妙搭应用属于用户资产。默认用 `--as user`;认证、scope、exit-10、高风险确认、`_notice` 等通用处理只读 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md),不要在本 skill 里复制。妙搭应用有两条开发路径:**本地开发**(拉源码本地写)/ **云端会话**(妙搭 AI 生成)。
SKILL.md:39来自说明文档
| 本地开发时 `.env.local` 损坏/丢失,重新拉取启动期环境变量 | `+env-pull` | [`lark-apps-env-pull.md`](references/lark-apps-env-pull.md) || 管理应用环境变量(查看/设置/删除) | `+env-list`, `+env-set`, `+env-delete` | [`lark-apps-env.md`](references/lark-apps-env.md) || 查线上日志、Trace、请求数、错误率、延迟、CPU、memory、PV/UV/访问量 | `+log-list`, `+log-get`, `+trace-list`, `+trace-get`, `+metric-list`, `+analytics-list` | [`lark-apps-observability.md`](references/lark-apps-observability.md) || 看表 / 看结构 / 初始化多环境 / 导入导出数据 / 变更追溯 / 行级审计 / dev→online 发布 / 时间点恢复 / 查 DB 用量 | `+db-table-list`、`+db-table-get`、`+db-env-create`、`+db-data-export`/`+db-data-import`、`+db-changelog-list`、`+db-audit-status`/`+db-audit-enable`/`+db-audit-disable`/`+db-audit-list`、`+db-env-diff`/`+db-env-migrate`、`+db-recovery-diff`/`+db-recovery-apply`、`+db-quota-get` | [`lark-apps-db.md`](references/lark-apps-db.md) || 逐条执行 SQL(SELECT / DML / DDL);建表 / 改表 / 写 SQL 的平台规范 | `+db-execute` | [`lark-apps-db-execute.md`](references/lark-apps-db-execute.md)(含「平台 SQL 规范」:审计列 / RLS / `user_profile` / 禁用 SQL / PG 陷阱) || 管理应用文件存储:上传/下载本地文件、列出/查看/删除已存文件、生成临时分享链接、查存储用量 | `+file-upload`/`+file-download`/`+file-list`/`+file-get`/`+file-sign`/`+file-delete`/`+file-quota-get` | [`lark-apps-file.md`](references/lark-apps-file.md) || 调试应用运行时缓存:查看/删除单个业务 key、清空指定环境缓存 | `+cache-get`/`+cache-delete`/`+cache-clear` | [`lark-apps-cache.md`](references/lark-apps-cache.md) |

创意设计流程会创建独立的妙搭应用仓库,提交、推送并发起线上发布,而不仅是生成 HTML。

查看原文
creative-design/creative-design.md:18来自说明文档
3. 列出 todo 清单。4. 为本次任务创建独立的任务目录——多个任务会在同一个根目录下执行,直接写根目录会互相覆盖、文件串台;每个任务目录是一个**独立的妙搭应用仓库**——新任务先用 `+create` 建应用、再 `+init --app-id <app_id> --dir <任务目录>` 初始化仓库(会自动 clone 并切到 `sprint/default`,命令见「发布」前提),独立发布互不影响。把资源复制进任务目录,在其中创建交付物。用图片素材提升美观度与丰富度、或需要有依据的内容时,按「图像素材与外部信息」补充。5. (如有)自检React + Babel路径是否正确;ReactDOM.createRoot 是否参数正确,对应元素是否存在6. 收尾:提交你的改动。7. 发布:把产物发布到妙搭拿到可访问链接(见下方「发布」)。写完不发布,用户拿不到线上链接。8. 极其简短地总结——只讲注意事项与后续步骤,并给出发布后的可访问链接。
creative-design/creative-design.md:208来自说明文档
```bash# 1. 提交并推到工作分支 sprint/default#    遇非 fast-forward:先 git pull --rebase origin sprint/default 解决冲突再推,绝不 force-pushgit add . && git commit -m "feat: ..." && git push origin sprint/default# 2. 发起部署(记下返回的 release_id),然后轮询状态直到 finished / failed:#    publishing → 继续轮询;finished → 输出含可分享的 online_url,直接返回给用户;failed → 按输出中的 error_logs 报告失败原因lark-cli apps +release-create --app-id <app_id> --as userlark-cli apps +release-get --app-id <app_id> --release-id <release_id> --as user```

多个破坏性操作设置了预览或确认门槛,包括环境变量删除、整环境缓存清空、数据库恢复和角色删除。

查看原文
SKILL.md:157来自说明文档
- **预授权判定**:判断用户是否表达了"放手做完、不用中途逐步问我"的意图——明确免确认(如"别问 / 直接做 / 自己定"),或要求一气呵成做到完成(如"做完部署上线给我")。是 → 整个流程按合理默认往下走、不再逐步确认(含 clone 到派生目录、发布等);否 → 缺失参数(如目录)该问就问、高影响动作先确认。- **禁止预授权判定底线**(即便已预授权也不豁免):① 会删/丢数据或不可逆的 DB 操作(判据见 [`lark-apps-db-execute.md`](references/lark-apps-db-execute.md))先 `--dry-run` 确认;② `+role-delete`、`+role-member-remove --all`、批量移除成员必须先确认 app、role、成员范围和后果,不能从泛化"直接做"推导出 `--yes`;命令式"删除/移除某对象"只确定操作目标,不等于用户已确认不可逆后果,未明确确认时应在说明影响后停下请求确认;③ `+html-publish` 体积超限时(判据见 [`lark-apps-html-publish.md`](references/lark-apps-html-publish.md)),立即停止并转述超限项;④ `+cache-clear` 会清空整个环境的缓存,「用户让我清缓存」只确定了操作目标、不等于确认了这次清空——未拿到对「清空该环境」的明确确认表述时,只出 `--dry-run` 预览或停下请求确认,不得首次调用即自带 `--yes`(判据表见 [`lark-apps-cache.md`](references/lark-apps-cache.md))。
references/lark-apps-db.md:247来自说明文档
**`+db-recovery-diff`**:预览把库恢复到 `--target` 时间点会带来哪些变更(受影响的表、行数、预计耗时),不落地。同样需 `spark:app:write` scope。**`+db-recovery-apply`(高危)**:把库恢复到某个时间点,**会覆盖当前数据**,不可逆,必须带 `--yes`。- 可恢复窗口最长 **7 天**,且不早于**最近一次 `+db-env-migrate`**;超出窗口的目标会被拒。- 目标时间点与当前库一致时返回 `no_changes`(空操作),不算失败。- 动手前务必先 `+db-recovery-diff` 给用户确认。

随附的设计组件会与父页面通信,并可把设计状态、演示备注或完整 deck HTML 发送给宿主页面。

查看原文
creative-design/starter-components/design-canvas.jsx:223来自代码
// ─────────────────────────────────────────────────────────────const DC_STATE_FILE = '.design-canvas.state.json';// Persist a sidecar file back to the host.function miaodaWriteFile(path, content) {  try {    window.parent.postMessage({ type: 'miaoda:bridge:write-file', path: path, content: content }, '*');  } catch (e) {    /* no parent — ignore */  }  return Promise.resolve();}
creative-design/starter-components/deck-stage.js:2393来自代码
      }));      // Forward to parent so the host can persist mutations (the CustomEvent      // cannot cross iframe boundaries). detail.slide is an Element and can't      // survive structured-clone, so only the scalars cross.      try {        window.parent.postMessage({          type: 'miaoda:deck:deck-changed',          action: detail.action, from: detail.from, to: detail.to,          html: this.outerHTML,          notes: this._notesForEmit(),        }, '*');      } catch (e) {}    }

该 Skill 以用户身份管理妙搭应用资产;仅在 CLI 明确报告未登录或缺少相应 scope 时才触发应用域登录。

查看原文
SKILL.md:13来自说明文档
妙搭应用属于用户资产。默认用 `--as user`;认证、scope、exit-10、高风险确认、`_notice` 等通用处理只读 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md),不要在本 skill 里复制。妙搭应用有两条开发路径:**本地开发**(拉源码本地写)/ **云端会话**(妙搭 AI 生成)。
SKILL.md:17来自说明文档
妙搭应用是用户的个人资产,统一 `--as user`(见开头)。已有用户身份可用时直接执行业务命令,**不要为了预防权限问题主动重新登录**,否则可能中断原任务并触发不必要的设备授权。仅当 CLI 明确返回未登录或缺少本域 scope 时,一次性执行:```bashlark-cli auth login --domain apps```

画布导出会复制所选画板的 DOM 和计算样式、内联字体与图片资源,并在用户选择下载时生成 PNG 或独立 HTML 文件。

查看原文
creative-design/starter-components/design-canvas.jsx:969来自代码
// Per-artboard export (kind: 'png' | 'html'). Both paths share the same// self-contained clone: computed styles baked in, @font-face / <img> /// inline-style background-image urls inlined as data URIs. PNG wraps the// clone in foreignObject→canvas at 3× the artboard's natural width×height// (same pipeline the host uses for page captures); HTML wraps it in a// minimal standalone document. Both are independent of viewport zoom.async function dcExport(node, w, h, name, kind) {  try { await document.fonts.ready; } catch {}
creative-design/starter-components/design-canvas.jsx:1206来自代码
            </button>            {menuOpen && (              <div className="dc-menu" onPointerDown={(e) => e.stopPropagation()}>                <button onClick={() => doExport('png')}>下载 PNG</button>                <button onClick={() => doExport('html')}>下载 HTML</button>                <button className="dc-danger"                  onClick={() => { if (confirming) { setMenuOpen(false); onDelete(); } else setConfirming(true); }}>                  {confirming ? '确认删除' : '删除'}                </button>              </div>

调整面板的值不是仅用于预览:每次设置都会向父页面发送修改,注释明确说明宿主会据此重写磁盘上的 EDITMODE 块。

查看原文
creative-design/starter-components/tweaks-panel.jsx:175来自代码
// ── useTweaks ───────────────────────────────────────────────────────────────// Single source of truth for tweak values. setTweak persists via the host// (miaoda:tweaks:set-keys → host rewrites the EDITMODE block on disk).function useTweaks(defaults) {  const [values, setValues] = React.useState(defaults);  // Accepts either setTweak('key', value) or setTweak({ key: value, ... }) so a  // useState-style call doesn't write a "[object Object]" key into the persisted  // JSON block.  const setTweak = React.useCallback((keyOrEdits, val) => {    const edits = typeof keyOrEdits === 'object' && keyOrEdits !== null      ? keyOrEdits : { [keyOrEdits]: val };    setValues((prev) => ({ ...prev, ...edits }));    window.parent.postMessage({ type: 'miaoda:tweaks:set-keys', edits }, '*');    // Same-window signal so in-page listeners (deck-stage rail thumbnails)    // can react — the parent message only reaches the host, not peers.    window.dispatchEvent(new CustomEvent('tweakchange', { detail: edits }));  }, []);
从这里开始 · 工作说明SKILL.md
lark-apps
连线表示工作说明包含的模块,不是实际运行顺序。点击模块可查看原文。 另有 2 个章节,可在原文件中查看。

文件引用关系图

40 处引用
哪些文件发起引用引用了什么
连线表示真实的文件引用,不是运行顺序。点击节点可高亮相关连线,并查看具体文件和原文位置。虚线表示还有文件需要定位。
文件与检查记录54 个文件

检查范围与遗漏

  • creative-design/agents/assets/vision-probe.png已核验为非程序资源 · 263 B
逐文件查看涉及的内容

下方列出本次涉及的原文范围;纳入检查不代表已查清所有问题。

  • SKILL.md已纳入全文
  • creative-design/creative-design.md已纳入全文
  • references/lark-apps-automation.md已纳入全文
  • references/lark-apps-cache.md已纳入全文
  • references/lark-apps-cloud-dev.md已纳入全文
  • references/lark-apps-create.md已纳入全文
  • references/lark-apps-db-execute.md已纳入全文
  • references/lark-apps-db.md已纳入全文
  • references/lark-apps-env-pull.md已纳入全文
  • references/lark-apps-env.md已纳入全文
  • references/lark-apps-file.md已纳入全文
  • references/lark-apps-get.md已纳入全文
  • references/lark-apps-git-credential.md已纳入全文
  • references/lark-apps-html-publish.md已纳入全文
  • references/lark-apps-init.md已纳入全文
  • references/lark-apps-list.md已纳入全文
  • references/lark-apps-local-dev.md已纳入全文
  • references/lark-apps-observability.md已纳入全文
  • references/lark-apps-openapi-key.md已纳入全文
  • references/lark-apps-plugin-install.md已纳入全文
  • references/lark-apps-plugin-list.md已纳入全文
  • references/lark-apps-plugin-uninstall.md已纳入全文
  • references/lark-apps-release-create.md已纳入全文
  • references/lark-apps-release-get.md已纳入全文
  • references/lark-apps-release-list.md已纳入全文
  • references/lark-apps-role.md已纳入全文
  • references/lark-apps-session-messages-list.md已纳入全文
  • references/lark-apps-update.md已纳入全文
  • references/lark-apps-user-id-convert.md已纳入全文
  • creative-design/starter-components/android-frame.jsx已纳入全文
  • creative-design/starter-components/animations.jsx已纳入全文
  • creative-design/starter-components/browser-window.jsx已纳入全文
  • creative-design/starter-components/deck-stage.js已纳入全文
  • creative-design/starter-components/design-canvas.jsx已纳入全文
  • creative-design/starter-components/ios-frame.jsx已纳入全文
  • creative-design/starter-components/macos-window.jsx已纳入全文
  • creative-design/starter-components/tweaks-panel.jsx已纳入全文
  • creative-design/assets/index.html已纳入全文
  • creative-design/references/animated-video.md已纳入全文
  • creative-design/references/charts.md已纳入全文
  • creative-design/references/data-report.md已纳入全文
  • creative-design/references/frontend-design.md已纳入全文
  • creative-design/references/hi-fi-design.md已纳入全文
  • creative-design/references/interactive-prototype.md已纳入全文
  • creative-design/references/make-a-deck.md已纳入全文
  • creative-design/references/visual-exposure.md已纳入全文
  • creative-design/references/wireframe.md已纳入全文
  • references/lark-apps-access-scope-set.md已纳入全文
  • creative-design/agents/fork-verifier-agent.md已纳入全文
  • creative-design/agents/vision-probe-agent.md已纳入全文
  • creative-design/references/aily.md已纳入全文
  • creative-design/references/claude.md已纳入全文
  • creative-design/references/codex.md已纳入全文
  • references/lark-apps-access-scope-get.md已纳入全文

这份报告只针对上方版本。我们看了拿到的代码和说明文件,没有实际运行 Skill,也没有检查它另外安装的软件包。因此,这不是“保证安全”的承诺;换了版本或使用环境,结果也可能不同。

  • SKILL.md工作说明
  • creative-design/agents/fork-verifier-agent.md配套文件
  • creative-design/agents/vision-probe-agent.md配套文件
  • creative-design/assets/index.html配套文件
  • creative-design/creative-design.md配套文件
  • creative-design/references/aily.md配套文件
  • creative-design/references/animated-video.md配套文件
  • creative-design/references/charts.md配套文件
  • creative-design/references/claude.md配套文件
  • creative-design/references/codex.md配套文件
  • creative-design/references/data-report.md配套文件
  • creative-design/references/frontend-design.md配套文件
  • creative-design/references/hi-fi-design.md配套文件
  • creative-design/references/interactive-prototype.md配套文件
  • creative-design/references/make-a-deck.md配套文件
  • creative-design/references/visual-exposure.md配套文件
  • creative-design/references/wireframe.md配套文件
  • creative-design/starter-components/android-frame.jsx脚本
  • creative-design/starter-components/animations.jsx脚本
  • creative-design/starter-components/browser-window.jsx脚本
  • creative-design/starter-components/deck-stage.js脚本
  • creative-design/starter-components/design-canvas.jsx脚本
  • creative-design/starter-components/ios-frame.jsx脚本
  • creative-design/starter-components/macos-window.jsx脚本
  • creative-design/starter-components/tweaks-panel.jsx脚本
  • references/lark-apps-access-scope-get.md配套文件
  • references/lark-apps-access-scope-set.md配套文件
  • references/lark-apps-automation.md配套文件
  • references/lark-apps-cache.md配套文件
  • references/lark-apps-cloud-dev.md配套文件
  • references/lark-apps-create.md配套文件
  • references/lark-apps-db-execute.md配套文件
  • references/lark-apps-db.md配套文件
  • references/lark-apps-env-pull.md配套文件
  • references/lark-apps-env.md配套文件
  • references/lark-apps-file.md配套文件
  • references/lark-apps-get.md配套文件
  • references/lark-apps-git-credential.md配套文件
  • references/lark-apps-html-publish.md配套文件
  • references/lark-apps-init.md配套文件
  • references/lark-apps-list.md配套文件
  • references/lark-apps-local-dev.md配套文件
  • references/lark-apps-observability.md配套文件
  • references/lark-apps-openapi-key.md配套文件
  • references/lark-apps-plugin-install.md配套文件
  • references/lark-apps-plugin-list.md配套文件
  • references/lark-apps-plugin-uninstall.md配套文件
  • references/lark-apps-release-create.md配套文件
  • references/lark-apps-release-get.md配套文件
  • references/lark-apps-release-list.md配套文件
  • references/lark-apps-role.md配套文件
  • references/lark-apps-session-messages-list.md配套文件
  • references/lark-apps-update.md配套文件
  • references/lark-apps-user-id-convert.md配套文件

代码和说明中提到的操作

运行命令
SKILL.md:17来自说明文档
妙搭应用是用户的个人资产,统一 `--as user`(见开头)。已有用户身份可用时直接执行业务命令,**不要为了预防权限问题主动重新登录**,否则可能中断原任务并触发不必要的设备授权。仅当 CLI 明确返回未登录或缺少本域 scope 时,一次性执行:
SKILL.md:19来自说明文档
```bashlark-cli auth login --domain apps
SKILL.md:80来自说明文档
```bash# 读取协作者和当前协作策略
读取密钥或账号配置
SKILL.md:38来自说明文档
| 开发已有应用 / 初始化本地仓库(开发方式已定为本地后;先解析 app_id,勿 `+create` 新建) | `+init`(或手动 `+git-credential-init` + 原生 git)。**执行前必读** [`lark-apps-local-dev.md`](references/lark-apps-local-dev.md),含端到端流程和领域规则 | [`lark-apps-init.md`](references/lark-apps-init.md | 本地开发时 `.env.local` 损坏/丢失,重新拉取启动期环境变量 | `+env-pull` | [`lark-apps-env-pull.md`](references/lark-apps-env-pull.md) || 管理应用环境变量(查看/设置/删除) | `+env-list`, `+env-set`, `+env-delete` | [`lark-apps-env.md`](references/lark-apps-env.md) |
SKILL.md:51来自说明文档
| 云端 Agent 生成/迭代应用(开发方式已定为云端后) | `+session-create` -> `+chat` -> `+session-get` | [`lark-apps-cloud-dev.md`](references/lark-apps-cloud-dev.md) || 管理妙搭应用开放 API Key(创建/查看/启停/重置/删除凭证;密钥仅 create/reset 一次性返回) | `+openapi-key-list/get/create/update/enable/disable/delete/reset` | [`lark-apps-openapi-key.md`](references/lark-apps-openapi-key.md) || 管理妙搭应用自动化触发器(定时/记录变更/Webhook/飞书审批四类触发器的查询/创建/更新/启停;Webhook URL·Token 一次性回显、不落盘) | `+automation-list/get/create/update/enable/disable` | [`lark-apps-automation.md`](references/lark-apps-automation.md) |
SKILL.md:118来自说明文档
- 发布态链接来源:`+release-get` 轮询 `finished` 给 `online_url` / `failed` 给 `error_logs`(html / frontend / full_stack 统一走 `+release-get`)。- html 应用的主链路是创意模式开发方式:按 [`lark-apps-local-dev.md`](references/lark-apps-local-dev.md) 初始化仓库、在仓库内产出 HTML 及关联文件,并通过 git commit / git push / `+release-create` / `+release-get` 发布部署。任何 git 操作(clone / pull / push)报错时,先执行 `lark-cli apps +git-credential-init --app-id <app_id> --as user` 刷新本地 Git 凭证,再重试原 git 命令。如果刷新凭证也失败,**停止并向用户报告**:原始 git 错误、凭证刷新失败原因,以及是否可能是当前环境(操作系统、沙箱)限制导致(如 macOS Keychain 在沙箱中不可用、Linux 加密文件目录不可写等)。不要改走 `+html-publish`,也不要把 `+html-publish` 当作本地开发链路的 fallback。- 创意模式(html)应用的链接格式为 `https://{租户域名}/page/{meta_token}`,**开发态和发布态是同一个链接**(区别于 full_stack 应用两者分开)。此链接形似飞书文档链接。`+get --app-id <meta_token>` 可获取应用信息(含 `app_id`),`+get --app-id <app_id>` 可获取 `meta_token`。看到 `/page/xxx` 链接时,它是妙搭创意模式应用,不要当成飞书文档跳过 
连接外部网站
creative-design/starter-components/animations.jsx:587来自代码
        {playing ? (          <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">            <path d="M3.33333 1.33398C2.59695 1.33398 2 1.93094 2 2.66732V13.334C2 14.0704 2.59695 14.6673 3.33333 14.6673H4.66667C5.40305 14.6673 6 14.0704 6 13.334V2.66732C6 1.93094 5.40305 1.33398 4.66667 1.33398H3.33333Z" fill="currentC 
creative-design/starter-components/animations.jsx:592来自代码
        ) : (          <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">            <path d="M14.0489 9.13127C14.873 8.60116 14.873 7.39754 14.0489 6.86743L4.74461 0.882617C3.84764 0.305661 2.66699 0.948902 2.66699 2.01454V13.9842C2.66699 15.0498 3.84764 15.693 4.74461 15.1161L14.0489 9.13127Z" fill="currentCol 
creative-design/starter-components/deck-stage.js:864来自代码
      Promise.all(pending.map((href) =>        fetch(href).then((r) => (r.ok ? r.text() : '')).catch(() => '')          .then((text) => { this._xoCssCache.set(href, text); })
读取文件
creative-design/starter-components/design-canvas.jsx:371来自代码
    const onDocDown = (e) => {      if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);    };
creative-design/starter-components/design-canvas.jsx:399来自代码
          className="dc-zoom-btn dc-zoom-trigger"          onClick={() => setOpen((o) => !o)}        >
creative-design/starter-components/design-canvas.jsx:409来自代码
            {DC_ZOOM_PRESETS.map((p) => (              <button type="button" key={p} onClick={() => { onZoomTo(p); setOpen(false); }}>                <span>{p}%</span>
修改文件
creative-design/starter-components/design-canvas.jsx:226来自代码
// Persist a sidecar file back to the host.function miaodaWriteFile(path, content) {  try {
creative-design/starter-components/design-canvas.jsx:265来自代码
    const t = setTimeout(() => {      miaodaWriteFile(DC_STATE_FILE, JSON.stringify({ sections: state.sections })).catch(() => {});    }, 250);
安装其他软件包
references/lark-apps-local-dev.md:16来自说明文档
`+create(full_stack)` -> `+init`(或手动 `+git-credential-init` + `git clone`)-> 读仓库 Skill -> `npm install && npm run dev` -> 按需 `+db-*` 调库 -> 非自动化改动按本页 commit/push/release;包含自动化 handler 时,在任何 release 前转到 [automation SOP](lark-apps-automation.md),由它接管状态门禁和完整发布。
references/lark-apps-local-dev.md:28来自说明文档
cd ./approval-appnpm installnpm run dev
references/lark-apps-local-dev.md:53来自说明文档
cd ./json-toolnpm installnpm run dev
读取了多少行
9,779
文件校验值(用于核对版本)
c607e0c1521bc701610527147736214bfd8975eff57158e8ca8e95cb16185162