@kentcdodds: 这太不可思议了。你可以在@kodykoala内运行一个全栈@remix_run应用:https://kody.codes/@kentcdodds/packag…
摘要
Kent C. Dodds宣布推出一个针对Kody的包应用套件,它能够运行全栈Remix应用,并集成了设计令牌、PWA支持、错误处理和实时同步等功能。
查看缓存全文
缓存时间: 2026/09/16 05:54
这太疯狂了。你可以在 @kodykoala 内运行一个完整的 @remix_run 应用:https://t.co/1ByZtRWdjX Kody 包运行在动态 Worker 中。简直酷毙了。它拥有执行你 Kody 账户所能做任何事情的权限。这是构建个人软件最简单的方式。https://t.co/mZGKwm1VG5
@kentcdodds/package-app-kit — Kody 公共包
来源:https://kody.codes/@kentcdodds/package-app-kit
← 公共包 (https://kody.codes/community)
设计令牌、PWA 安装/更新、关于/版本信息、缓存辅助工具,以及用于 Kody 包应用的可选实时笔记同步功能。
仓库 (https://kody.codes/@kentcdodds/package-app-kit)
文件 (https://kody.codes/@kentcdodds/package-app-kit/tree/main)
- 应用 (https://kody.codes/community?category=apps)
- app - pwa - design - cache - kit
版本 0.1.0
许可
发布于 2026年9月15日
固定提交 7ca952c
评分 暂无评分
分叉 0
适配工作量 —
@kentcdodds/package-app-kit
Kody 包应用的运行时设计/PWA 工具包。
意图
为 Kent(以及未来的 @kody 消费者)提供一个精简的私有工具包,让每个包应用都能共享:
- CSS 自定义属性设计令牌(包括 间距比例
--pak-space-1…8+pak-stack/pak-cluster/pak-inset)和实用的原生 UI(包括一个受 sonner 启发 的 toast 组件) - 按压反馈 / 乐观 UI: 点击时立即显示挂起状态;忙碌标签使用
spin-delay计时(无闪烁) - ErrorBanner: 用于验证 / 关于页面 / SSR 错误的共享警告横幅(
app/ui/error-banner.tsx+./error-display) - 零累积布局偏移(CLS)偏好: “更新可用“是一个固定的、可关闭的 toast(不是流内横幅);临时 UI 不占用文档流
- Header 安装图标(Lucide
download,保留槽位,无 CLS)触发原生安装提示(beforeinstallprompt→event.prompt()),仅在 UA 确实是 iOS 时(固定覆盖层)显示 iOS 添加到主屏幕。为不直观/仅图标控制添加工具提示。 /about页面,包含提交 SHA/消息、提交/发布日期 + 相对时间、包代码链接,以及手动更新检查——通过 record-version 模式实现(不放在首页上)。- Remix 示例 实时演示位于
app/下({ fetch }重载包装器 +remix/ui岛屿),展示令牌、笔记、安装、关于和更新检查功能。 - 访问时检查更新 → 刷新提示
- 用于破坏性操作的双重检查辅助工具(两步 + 输入确认;笔记使用
NotesDemo+DoubleCheckButton,支持乐观 UI 和 PE) packageStorage模式迁移(./storage-migrations)—— 稳定的工具包子路径,重新导出@kentcdodds/package-storage-migrations(版本键、有序的up步骤、隔离的记忆化运行器;调用者始终传递 storage)- 可选的实时笔记同步(
./realtime+./realtime-client)—— WorkerbroadcastNotesChanged/handleRealtimeEvent;浏览器端connectPackageRealtime(参见 AGENTS L3) - Lucide SVG 图标(ISC 许可)—— 通过
scripts/add-lucide-icon.mjs签入app/icons/(无完整 Lucide 运行时依赖) - 客户端缓存辅助工具(TanStack Query 核心 + IndexedDB)和服务器缓存(@epic-web/cachified +
packageStorage) - 带有僵尸防护的服务 Worker 辅助工具(版本化缓存、清理、谨慎的
skipWaiting/clients.claim,注销过期的 SW) - 桌面 + 移动端友好的布局(流体宽度、大型点击目标、无移动端专属文案)
入门模板位于此仓库中 的 starter-remix/(脚手架工具会将该目录嵌入到新的 Artifacts 包中并重命名占位符)。没有单独的 @kentcdodds/package-app-starter 包。此包自身的实时演示(kody.app → app/router.ts)是 Remix 导出形状,用于工具包展示,不是脚手架工具复制的内容。归档的 fetch 模板:starter-fetch/。归档的 Remix 前工具包演示:archive/fetch-demo/。目前为私有 @kentcdodds;稍后提升至 @kody。
工具包演示品牌
实时工具包演示使用赛车手 Kody 作为应用内徽标(半身头部、全身主角)以及列表/收藏夹/PWA 标志(赛车手半身像——非 Remix R + 彩虹条纹符号)。设计令牌默认为 Remix-dark(#0a0a0a/#121212),主色为青色,条纹为次要色。脚手架生成的应用仍会包含一个占位符 .kody/icon——请根据脚手架后检查清单生成独特的标志。私有托管应用:通过 kody.codes 上的打开包应用打开。当你需要新的会话或 service worker 时,从包页面重新打开,然后在更新 toast 出现时选择刷新。
应用内徽标: 从返回 image/png 的应用路由提供 header/hero/favicon 标志(与 iconPngResponse//icons/... 相同的模式),并在标记中指向 routes\....href()。使用 public/ + \_assets 存放 CSS、sw.js 和客户端包。
技术栈说明
实时工具包演示 是一个 Remix 示例,位于框架无关的宿主合同下(每个条目都是挂载剥离路径上的 fetch 处理器):
"kody": {
"app": {
"entry": "./app/router.ts",
"client": "./app/assets/entry.ts",
"assets": "./public"
}
}
演示/入门模板自身拥有的示例样板:根 tsconfig.json 包含 "jsx": "react-jsx" + "jsxImportSource": "remix/ui",在 app/router.ts 中进行重载 + export default { fetch },以及带有浏览器注册表的 clientEntry('kody:app#Name', ...) 岛屿。没有 kody.app.runtime。演示控制器使用相对 ../src/... 路径导入工具包辅助工具(此包不得通过 kody:@kentcdodds/package-app-kit 依赖自身)。
脚手架生成的应用复制 starter-remix/(相同的示例)并通过 kody:@kentcdodds/package-app-kit/... 导入工具包。
库消费者仍然获得 Worker HTML 辅助工具 + 可选的双路径客户端(packageContext.clientModuleUrl,临时的 ./client 启动)。对于 Remix 应用,优先使用平台 remix/ui——不要添加 @remix-run/ui 导入映射或臃肿的 remix 元包作为运行时依赖。
安装 / 导入
import themeCss from 'kody:@kentcdodds/package-app-kit/styles'
import { toastCss, toastHostHtml } from 'kody:@kentcdodds/package-app-kit/ui'
import { createDoubleCheck, createTypeToConfirm, } from 'kody:@kentcdodds/package-app-kit/double-check'
import { installChromeHtml } from 'kody:@kentcdodds/package-app-kit/install'
import { formatAboutPageData, aboutPageHtml } from 'kody:@kentcdodds/package-app-kit/about'
import { kitServedManifestIcons, iconPngResponse } from 'kody:@kentcdodds/package-app-kit/icons'
import { appShellHtml } from 'kody:@kentcdodds/package-app-kit/app-shell'
import { clientBootResponse, clientModuleResponse } from 'kody:@kentcdodds/package-app-kit/client'
import recordVersion from 'kody:@kentcdodds/package-app-kit/record-version'
import checkForUpdate from 'kody:@kentcdodds/package-app-kit/update-check'
import { createPersistedQueryClient } from 'kody:@kentcdodds/package-app-kit/client-cache'
import { createServerCachified } from 'kody:@kentcdodds/package-app-kit/server-cache'
import { renderServiceWorker, buildWebManifest } from 'kody:@kentcdodds/package-app-kit/sw'
import { runPackageStorageMigrations, createMigrationRunner, } from 'kody:@kentcdodds/package-app-kit/storage-migrations'
import { createNotesRealtimeHandler, broadcastNotesChanged, } from 'kody:@kentcdodds/package-app-kit/realtime'
import { connectPackageRealtime } from 'kody:@kentcdodds/package-app-kit/realtime-client'
始终从 packageContext.appBasePath + packageContext.hostedUrl 构建应用内 URL。参见 AGENTS.md 了解采用层级(纯 CSS → fetch 处理器 PWA → Remix → 可选实时 L3)、令牌/类契约、安装客户端要求以及脚手架工具手册。Fetch 处理器应用可以使用 ./app-shell(appShellHtml)而不是手动编写文档。
发布后操作
对于此工具包(演示关于/更新检查),调用工具包导出:
import recordVersion from 'kody:@kentcdodds/package-app-kit/record-version'
await recordVersion({ sha: '', message: '', committedAt: '', })
脚手架生成的消费者应用拥有自己的 ./record-version,写入该应用的 packageStorage(参见 starter-remix/src/record-version.ts)。发布脚手架生成的应用后,调用 kody:@scope/app/record-version——而不是工具包的导出。
图标 + 可安装性
列表/身份标志(包、仓库、社区卡片): 将 .kody/icon.png(也支持 .svg/.webp/.jpg/.jpeg)放入。新包使用 .kody/icon——不要脚手架根目录的 community-icon.*。根目录的 icon.*/community-icon.* 保留为永久的平台别名。将 PWA 图标(icons/icon-192.png,public/)放在 .kody/ 之外。此工具包包含 .kody/icon.png;脚手架工具生成 .kody/icon.svg(文本),因为 packageSave 无法写入二进制文件。仍然欢迎设计/生成的图标以提升精致度;空的 icons: [] 不会被推广。
PWA 安装(Chromium / Brave URL 栏): 需要一个包含 name/short_name、start_url、display 以及实际返回 200 状态码的 192 和 512 尺寸 PNG 图标的清单文件。此工具包嵌入了这些 PNG 并通过 ./icons(iconPngResponse/kitServedManifestIcons)提供它们,因此应用无需提交二进制 PWA 图标文件。仍可设计/生成图标以进行美化;空的 icons: [] 不会被推广。
buildWebManifest 默认 display: "standalone",并接受 fullscreen、orientation、categories 和额外的清单字段——当 iOS Safari 手势可能干扰应用时很有用。start_url/scope/id 位于 /packages/<slug>/ 下。每个 HTML 页面必须有 <manifest> 标签。清单响应使用 cache-control: no-store。SW 预缓存首页、/about、/notes、图标和清单,并首先通过网络获取清单,不缓存 403 响应。私有托管应用需要通过 kody.codes 进行打开包应用交接。已安装的 PWA 在品牌/图标网络请求在会话 cookie 过期后返回 403 时,可能仍然显示缓存的 HTML 外壳——从包页面重新打开,然后在更新 toast 出现时选择刷新。
入门模板 + 脚手架工具
参见 starter-remix/STARTER.md。执行 create-package-app 后,代理遵循 AGENTS.md 中的脚手架后检查清单(以及落入新包的 AGENTS.md 中的副本):独特的 .kody/icon 列表标志、PWA icons/icon-192.png + icons/icon-512.png、标题/描述、本地 record-version、Remix 示例提醒,以及与标志匹配的清单颜色。
通过一次执行调用创建一个新的私有 Remix 包应用:
import createPackageApp from 'kody:@kentcdodds/package-app-kit/create-package-app'
export default async function main() {
return await createPackageApp({
packageName: '@kentcdodds/my-notes', // 或叶子包 `my-notes`
title: 'My Notes',
})
}
Lucide 图标(签入的 SVG)
默认图标集:Lucide (https://lucide.dev/)(仓库 (https://github.com/lucide-icons/lucide))——ISC 许可,一致的 24×24 描边图标,纯 SVG。在 https://lucide.dev/icons 浏览名称。
在应用(及入门模板副本)中添加图标,无需打包完整的 Lucide 包:
node scripts/add-lucide-icon.mjs download trash-2 plus
# 写入 app/icons/{name}.svg + {name}.tsx 并镜像到 starter-remix/app/icons/
将生成的 Remix Handle 组件(<IconDownload />)与可见标签一起使用,或在仅图标时与 data-tip + aria-label 一起使用:
import { IconDownload } from '../icons/download.tsx'
import { IconTrash2 } from '../icons/trash-2.tsx'
<button>
<IconDownload /> 删除
</button>
归属说明作为 app/icons/ATTRIBUTION.md 发布。
packageStorage 迁移
使用版本键和有序迁移来演进持久的 packageStorage 模式。工具包子路径重新导出 @kentcdodds/package-storage-migrations;保持导入 kody:@kentcdodds/package-app-kit/storage-migrations,并始终传递调用者的 storage。
在启动时或第一个需要数据的请求时,为每个 Worker 隔离区运行一次(记忆化):
import { packageStorage } from 'kody:runtime'
import { createMigrationRunner, } from 'kody:@kentcdodds/package-app-kit/storage-migrations'
const ensureSchema = createMigrationRunner({
storage: packageStorage(),
versionKey: 'my-app:schema-version',
migrations: [
{
version: 1,
name: 'notes-to-document',
async up(storage) {
const legacy = await storage.get('notes-v1')
if (Array.isArray(legacy)) {
await storage.set('notes', { items: legacy })
await storage.delete?.('notes-v1')
}
},
},
],
})
// 在 loader / action 中:
await ensureSchema()
实时演示笔记存储(app/data/notes.ts)展示了此模式的端到端应用。
报告此列表
登录 以报告此列表。
相似文章
@kentcdodds: 你能相信这是由一个独立开发者在一天内完成的吗? https://github.com/kentcdodds/kody/releases/tag/v2026.08.1…
Kody 是一个面向 AI 代理的便携式个人助理平台,基于 Cloudflare Workers 和 Model Context Protocol 构建,能够在不同主机间启用记忆、代码和自动化管理。
@kentcdodds: 快速演示,展示我如何使用 @kodykoala 包的 Webhook 与 @raycast 集成使用 Kody
Kent C. Dodds 展示了如何使用 Kody 包的 Webhook 来与 Raycast 集成以实现自动化。
@kentcdodds: @kodykoala 的一个好处是它没有自带由 Kody 托管的集成功能。相反…
Kody Koala 是一款开发者工具,帮助用户创建自己的集成,而不是依赖托管的集成,从而让用户拥有完全的控制权。
@kentcdodds: 我有一个小型(约19k)视频应用,这周将发布。我遇到了一个bug,fable和我多次尝试都无法修复…
Kent C. Dodds发推称,一个名为Fable的AI编程助手将他小的React视频应用重写为Remix,从而解决了一个一直存在的bug。
@kentcdodds: Playing with @DevinAI so naturally I had it create a Devin package on @kodykoala https://heykody.app/@kentcdodds/devin…
Kent C. Dodds shares a Kody community package that provides an SDK for the Devin v3 API, enabling automated management of Devin sessions, knowledge, playbooks, and schedules.