卡片外框与对话框
卡片的标题栏、概览图块和对话框都由应用绘制,而不是你的页面——因此它们看起来是原生的,在卡片暂停时依然有效,也会显示在手机上。你只负责设置内容。
想调用多少次都行。 应用会对这些更新限流(标题每分钟 30 次;状态、徽章和概览各每分钟 120 次;提醒每 10 秒一次),
而 SDK 会替你消化这些限制:对于 setTitle、setStatus、setBadge、setOverview 和 attention,每个方法同一时间只发送一个调用,
期间发起的调用会合并成一个、只保留最新的值,应用返回 RATE_LIMITED 时还会重试最新的值。它们永远不会因为限流而抛出异常——
每次渲染都更新也没问题。没有改变任何内容的更新不产生任何开销。
标题
await card.setTitle('Checkout tests') // null clears it显示在标题栏、侧边栏和小队(Squad)卡片中的名称。如果用户给卡片改过名,以用户起的名字为准;两者都没有时显示清单中的 displayName。
≤ 120 个字符;控制字符、双向文本字符和不可见字符会被去除。
状态
await card.setStatus('Running tests…', { busy: true }) // spinner
await card.setStatus('3 failed', { tone: 'danger' })
await card.setStatus(null) // clear标题栏中的一个标签,≤ 80 个字符。色调:default、accent、success、warning、danger。
徽章
await card.setBadge(3) // a count
await card.setBadge('NEW', { tone: 'accent' }) // or a short text, ≤ 12 characters
await card.setBadge(null) // clear概览图块
当用户把画布缩小到超过概览阈值时,每张卡片都会显示一个展示其关键信息的图块,而不是正文。你的卡片显示的就是你在这里设置的内容—— 卡片暂停时、在手机上也会继续显示。应用会记住它。
await card.setOverview({
primary: '3 failing', // big line, ≤ 160
secondary: 'checkout, auth', // small line, ≤ 160
progress: 0.8, // 0..1, a progress bar; null hides it
tone: 'danger',
icon: 'bug-ant'
})请保持它是最新的:在繁忙的画布上,这是大多数人唯一会看到的你的卡片内容。
应用能绘制的图标(heroicons,outline 风格):academic-cap、arrow-path、beaker、bell、
bolt、book-open、bug-ant、calendar、camera、chart-bar、chart-pie、
chat-bubble-left-right、check-circle、clock、cloud、code-bracket、command-line、
cpu-chip、cube、currency-dollar、document-text、exclamation-triangle、film、fire、
flag、folder、globe-alt、heart、inbox、key、light-bulb、link、list-bullet、map、
megaphone、moon、musical-note、newspaper、paper-airplane、pause、photo、play、
puzzle-piece、rocket-launch、server、shield-check、signal、sparkles、star、stop、
sun、table-cells、tag、trash、trophy、users、wrench-screwdriver(SDK 中的 HOST_ICON_NAMES 列表)。
在你自己的页面里,想画什么图标都可以。
提醒
await card.attention('needs-input', 'Pick a branch to deploy')
await card.attention('info') // a softer pulse
await card.attention('none') // clearneeds-input 会让卡片像等待用户的智能体一样闪烁,并把它列入收件箱(Inbox)。每 10 秒最多一次。第 1 版中没有声音,也没有系统通知。
当前显示的是什么。 应用会在重新加载、暂停和更新之间保留卡片的标题、状态、徽章、概览和提醒。card.context.chrome
告诉你的页面当前保存着什么,所以在重新加载前发出过提醒的卡片可以清除过时的闪烁:
const attention = card.context.chrome?.attention
if (attention && !stillNeedsTheUser()) await card.attention('none')
declare function stillNeedsTheUser(): boolean在旧版本的应用中没有 chrome——请把这种情况当作“未知”。
调整大小
const applied = await card.requestResize({ w: 640, h: 480 })
render(applied.w, applied.h)会被限制在清单的 minSize/maxSize 之间;返回实际应用的大小。它会像手动调整大小一样进入画布的撤销历史。
每 500 毫秒最多一次。用户也随时可以调整大小——用 card.lifecycle.onResized 监听。
打开链接
const opened = await card.openLink('https://github.com/acme/app/issues/42')应用会在它自己覆盖整个窗口的对话框中显示完整地址;只有在用户点击 Open link 之后,链接才会在用户的浏览器中打开。
只允许 https://,并且只能在卡片可见时调用(否则为 NOT_VISIBLE)。用户拒绝时返回 false。卡片不能让自己跳转,也不能打开窗口。
飞到另一张卡片
await card.focusCard(cardId)把镜头移到同一工作区的另一张卡片——适合做“带我去看失败的智能体”这类按钮。只能在你的卡片可见时调用,每 5 秒最多一次。
创建卡片
需要 canvas.spawn。
// A note next to this card, connected with an arrow from this card.
const noteId = await card.spawn('note', { title: 'Test report' })
await card.ports.send(noteId, 'summary', '# Report\n\nAll green.')
// Another copy of this card, with data for its first start.
await card.spawn('self', { init: { suite: 'e2e' }, connect: false })类型:self(你的卡片包的另一张卡片,首次启动时会以 card.spawnInit 收到 init)、note、todo、kanban、sticky。
新卡片会放在你的卡片旁边,并用一条从你的卡片出发的箭头相连,除非传入 connect: false。每张卡片最多 4 张,每分钟最多 4 张。
卡片信息
const info = await card.getInfo() // CardInstanceInfo, fresh from the app
render(info.instanceId, info.packageId, info.commit ?? 'dev folder', info.size)提示条
await card.ui.toast('Copied', { tone: 'success', durationMs: 2000 })卡片方框内的一条小提示,≤ 280 个字符,显示 1–15 秒,每 2 秒最多一条。
确认对话框
在卡片沙箱中,alert、confirm 和 prompt 什么也不做。请改为让应用来询问:
const ok = await card.ui.confirm({
title: 'Delete all saved runs?',
message: 'This removes 42 runs from this card. It cannot be undone.',
confirmLabel: 'Delete',
cancelLabel: 'Keep',
tone: 'danger'
})
if (ok) await card.storage.clear()应用会把它显示为覆盖整个窗口的它自己的对话框,而不是在你的卡片里:一个固定的标题说明你的卡片在请求确认,
你的 title 和 message 以引用的形式出现,然后是你的 confirmLabel(如果它读起来像取消/否/拒绝、提到了 NeuroSquad
或包含控制字符,就会被替换为应用的“Confirm”),以及应用自己的 Cancel。只能在卡片可见时调用,每分钟最多 10 次。
多张卡片的对话框会排队。
卡片菜单
在卡片的 ⋯ 菜单中,于应用自带的菜单项(Settings…、Reload、About…)之后添加最多 12 项。
await card.ui.setMenu([
{ id: 'rerun', label: 'Run again', icon: 'arrow-path', onSelect: () => void rerun() },
{ id: 'export', label: 'Copy report', icon: 'document-text', onSelect: () => void copyReport() },
{ id: 'reset', label: 'Reset', tone: 'danger', disabled: true }
])
// Or handle every choice in one place:
card.ui.onMenu((id) => card.log.info('menu', id))
declare function rerun(): Promise<void>
declare function copyReport(): Promise<void>每次调用都会替换之前的菜单项(每分钟最多 30 次)。onSelect 留在你的卡片里——不会发送给应用。
标签 ≤ 60 个字符;icon 取自宿主图标。
本页中除对话框和链接以外的一切,在卡片不在屏幕上时同样有效。对话框、链接、镜头聚焦和权限申请需要用户正在看:
否则会以 NOT_VISIBLE 失败。