@bud.sh/app

中文文档
0.8.1发布于 2026/11/06UNLICENSEDTypeScriptES Module近 30 天下载 2400

The app, its config, screen and design APIs

原始使用文档
文档目录13 节
  1. Features
  2. Installation
  3. Usage
  4. Plugins, storage and designs
  5. Screens
  6. Without Vite
  7. Task links
  8. Comments
  9. File and review links
  10. Migrating Git comments
  11. Security
  12. Development
  13. Related Packages

@bud.sh/app

Bud is a local companion for reviewing a web project: the app itself, its config, screen, design and adapter APIs, and the companion server a host starts. Its Vite plugin, @bud.sh/app/vite, hosts it beside your Vite dev server, and the package's bud CLI runs it without Vite. Bud browses your live pages, shows your routes side by side on a canvas, lets you browse, edit and review files, and keeps discussions on pages, code and tasks through your selected storage adapters. The interface uses Remix 3; your project can use any framework that runs on Vite.

Features

  • Pages - Your configured routes beside a browser of the live site, with tabs and history per workspace tab, and comments on elements you pick
  • Canvas - Every configured route as an always-current screenshot in light and dark, with comments whose pins follow their element
  • Branches - Screenshots of main and every activated branch beside the working tree, each built from its latest commit outside your checkout
  • Pickers - Comments record the element, its block and, with bud:react-grab, bud:remix or your own picker, its component and source line
  • Files - File tree, editor, diffs, history, staging and conflict resolution
  • Code comments - Discussions on selected lines that follow edits and stay readable when outdated
  • Tasks - Comments become tasks on a board that people and agents change live, with Beads as the default store; task designs can add fields such as priority or assignee
  • Agents - Comments become tasks that a coding agent (OpenCode) finishes in a sandbox, a local worktree or boat.dev, on its own dev/ branch: Agent view shows the live preview beside the agent's terminal and chat, the Agents screen lists every session, and nothing is pushed until someone approves
  • Hosting - The canvas, Pages, tasks and agents for a whole team on Cloudflare, for a GitHub repository
  • Custom screens - Your own Remix screens beside the built-ins, any of which you can turn off
  • Storage adapters - Beads stores tasks and discussions by default; custom adapters and the compatible Git comment store are explicit selections

Installation

One package holds the app, its Vite plugin and the bud CLI:

npm install -D @bud.sh/app

To try this repository's version instead, build and pack it:

pnpm --filter @bud.sh/app build
pnpm --filter @bud.sh/app pack --out /tmp/bud-app.tgz
# In your project
npm install -D /tmp/bud-app.tgz

Node 26.12 or newer is required.

Usage

Add the Vite plugin:

// vite.config.ts
import { bud } from '@bud.sh/app/vite'

export default {
  plugins: [bud()],
}

Add exactly one config file:

// bud.config.ts (or bud.config.js)
import { defineConfig } from '@bud.sh/app'

export default defineConfig({
  name: 'My project',
  routes: ['/', { id: 'product', path: '/products/123', title: 'Product' }],
  // port: 4000,                     // Bud's own port; omit to pick a free one
  // target: { port: 3000 },         // detected from Vite by default
  // comments: { remote: 'origin' },
  // plugins: [reactGrab()],         // from @bud.sh/app/plugins; Bud's DOM picker by default
})

Run your usual Vite dev command and open the printed Bud URL. The plugin only runs in development, and config changes restart it. It starts Bud's companion when Vite starts listening, finds your dev server's address, refreshes previews on hot updates and adds the small dev bridge Pages uses to follow your live pages; the bridge does nothing outside Bud's frames.

Plugins, storage and designs

Stores, the picker, the task design, extra screens and the factory's sandboxes and agent come from plugins, which @bud.sh/app/plugins exports: beads(), gitComments(), memory(), reactGrab(), react(), remix(), picker(), taskDesign(), local(), boat(), opencode() and definePlugin for your own. Tasks and discussions are Beads' unless a plugin provides one; storage: { work: false } or { threads: false } turns one off. designs.pages sets how the Pages sidebar names pages: by path (the default) or by title with the path beside it.

import { defineConfig } from '@bud.sh/app'
import { definePlugin, gitComments, taskDesign } from '@bud.sh/app/plugins'
import { tracker } from './bud/tracker.server.ts'

export default defineConfig({
  routes: ['/'],
  plugins: [
    definePlugin({ name: 'tracker', label: 'Tracker', work: tracker }),
    gitComments(),
    taskDesign('./bud/tasks.tsx'),
  ],
})

A plugin's store is a fully provided Effect layer using the WorkAdapter or ThreadAdapter service from @bud.sh/app/server, or a function making one for { project }; memoryAdapterLayer({ schema }) supplies both for fixtures. A shared layer is acquired once, and its resources close with the companion. Task designs are browser modules ending in .ts, .tsx, .js or .jsx inside the project, outside node_modules; Bud checks their paths before listening and their exports when opened. Only each store's public identity and connection state reach screens through project.storage; plugins and server configuration stay private.

Task designs default-export defineTaskDesign from @bud.sh/app/design. Its optional card, page, properties, actions, sections and column slots are Remix components. Omitted slots retain their built-in parts, which are exported for composition as TaskCardDefault, TaskPageDefault, SectionsDefault and ColumnDefault; properties and actions are empty until a design fills them. Slots receive validated work data, field rendering, navigation and explicit operations. Project context contains only its display id and name.

See the task design guide for the exported props and a compact-card example. The same browser-module registry and shared Remix import map serve screens and designs.

Screens

screens sets Bud's navigation, in order. Leave it out for Pages, Canvas, Tasks, Agents and Files (Agents once the factory is set up). Leave a built-in out to disable it, spread it to change its label or icon, and add your own screens as Remix component modules:

// bud.config.ts
import { canvas, defineConfig, files, pages } from '@bud.sh/app'

export default defineConfig({
  routes: ['/'],
  screens: [
    pages(),
    canvas(),
    { ...files(), label: 'Code' },
    { id: 'metrics', label: 'Metrics', icon: 'chart', module: './bud/metrics.tsx' },
  ],
})
// bud/metrics.tsx
import { Text, defineScreen } from '@bud.sh/app/screen'

export default defineScreen({
  load: async ({ project, signal }) => {
    let response = await fetch(new URL('/metrics.json', project.targetOrigin), { signal })
    return (await response.json()) as { visits: number }
  },
  render: (metrics) => <Text as="p">{metrics.visits} visits this week</Text>,
})

A custom screen's path defaults to /<id> and its icon to layers. Bud shows its loader until load settles and a retry card if it fails. Screens run only in the browser, inside Bud's page, and get the project with Bud's request capability, so treat them like the config. @bud.sh/app/screen also exports Bud's Button, Text, Loader, Spinner and field cards. Screens can't import CSS yet; Bud bundles each one with your project's Vite on first visit and again after you edit it.

Screens can own nested places. Keep the route map in a browser-safe module, then pass the same map as routes in both the config's screen and defineScreen:

// bud/metrics-routes.ts
import { get, route } from 'remix/routes'

export const metricsRoutes = route('/metrics', {
  index: get('/'),
  report: get('/reports/:id'),
})

metricsRoutes.report.href({ id: 'weekly' }) // /metrics/reports/weekly
import { Text, defineScreen } from '@bud.sh/app/screen'
import { metricsRoutes } from './metrics-routes.ts'

export default defineScreen({
  routes: metricsRoutes,
  render: (_data, context) => (
    <Text>{context.route === 'report' ? context.params.id : 'All reports'}</Text>
  ),
})

The config metadata allows startup validation without running screen modules on the server. Every route must stay under the screen's path. context.route narrows context.params; context.url carries the complete current location. Navigation within a screen preserves its component state and loaded data. Fetch route-specific updates from the component when its context changes; load runs only when the screen first opens.

Opened screens also stay mounted while hidden. context.active tells a screen when it is visible and owns the browser location. Background reconciliation can update its data, but should defer URL changes until it becomes active again.

Without Vite

npx bud [project-directory]                 # standalone, needs target.origin or target.port
npx bud doctor [project-directory]          # what's set up, and what the rest needs
npx bud comments migrate [project-directory] [--to bud:beads] [--dry-run]

The bud command comes with @bud.sh/app and needs target.origin or target.port in the config to serve. Previews opened this way can't be commented on; use the Vite plugin for that. Bud shows only what a project has set up; bud doctor says what that is and what the rest needs. bud capture is what a hosted Bud's builder runs.

The board lives at /tasks; each task has a typed /tasks/:id URL. Opening a task preserves the board's filters and scroll position, and Back returns to the same board. Copy link and modified clicks use the same route. Older ?issue= links redirect permanently after ID validation. Dots in hierarchical IDs are encoded by the route builder.

Comments

Comments use the selected thread adapter, which defaults to Beads. Initialize the project's Beads workspace explicitly before writing; Bud never creates one or chooses a hidden fallback. Authors come from your Git name and email on the server. One discussion can link to multiple tasks without duplicating its messages. Opening a discussion loads its messages; counts and truncation stay explicit when a backend returns a bounded view.

Writes use the discussion revision you last read. Conflicts retain the draft for review, and uncertain writes require checking the stored discussion before retrying. Sync is explicit and uses the selected adapter's existing remote configuration.

With gitComments(), discussions use the compatible bud/comments branch. Writes preserve your source branch, index and working files. Sync validates and merges fetched records, then pushes the exact validated commit without forcing. No other application storage selection writes this ref.

In Files, select lines and press Ctrl/⌘+Alt+M to comment. Save an editor draft first.

File links name the place directly. The route maps shared by the screen and link helpers live in @bud.sh/ui/routes.

PlaceURL
File or directory/files/src/app.ts
Working or staged review/files/review/working/src/app.ts
All changed files/files/review/working
Commit comparison/files/compare/HEAD...<full-object-id>/src/app.ts
Selected source lines/files/src/app.ts#L12-L20
Selected diff lines/files/review/working/src/app.ts#L12-R14

In diffs, L is the old side and R the new side. A copied selection opens its one file, including when copied from an all-files review. Its optional at query value is a SHA-256 content digest used to detect changed source; it is not an addressable Git blob. Compare endpoints accept HEAD, full object IDs and full refs/... names. The typed builder encodes them safely.

Files whose first segment is review, compare, blob or path use /files/path/<actual-path> to avoid route collisions. Existing query links redirect after their project and coordinates are validated. Foreign legacy links stay rejected.

New links belong to the companion's origin, and requests still require its session capability. A bookmark does not assert project identity if a different project later reuses that origin. Project IDs continue to scope local preferences.

Discussions use /comments/:id. Bud reads the selected thread adapter and opens the owning canvas, file or task screen, including its saved location and conversation. Copy-link controls use this address; older ?thread= links redirect permanently after validation. The URL carries only the thread ID, and the preview never receives the API capability.

Migrating Git comments

bud comments migrate --to bud:beads --dry-run
bud comments migrate --to bud:beads

The command loads the project's config and uses its selected thread adapter unless --to overrides it. Initialize the target store first. Migration does not need a preview server or target.origin, and it never changes the config or source Git comments ref.

Canvas and code captures, statuses, message order, original authors, timestamps and reply ancestry are preserved. Complete history can exceed the browser's message display limit; the source and target still enforce their configured byte limits. Existing source identities are skipped, so rerunning the command resumes a partial migration without duplicating threads. An uncertain write stops the run and is never retried automatically. Keep the source Git history until you have reviewed the imported discussions.

Security

Bud binds to loopback. Requests need a per-session capability that is never sent to the previewed page. Canvas captures pages in its own headless browser. Pages shows them in sandboxed frames on the project's own origin, which differs from Bud's, and follows them only through the dev bridge's postMessage protocol (@bud.sh/app/bridge); a site served from Bud's own origin is never framed.

Development

pnpm dev       # Bud and the marketing site with HMR
pnpm verify    # all checks, including an installed-tarball browser test

See AGENTS.md for the app's structure.

版本与发布记录

@bud.sh/app 共发布 12 个版本,首次发布于 2026/10/23;过去 12 个月发布了 12 个版本。

版本发布日期距今
0.8.1latest2026/11/062 天前
0.8.02026/10/2812 天前
0.7.02026/10/2712 天前
0.6.02026/10/2614 天前
0.5.12026/10/2316 天前
0.5.02026/10/2316 天前

关于 @bud.sh/app 的常见问题

@bud.sh/app 是什么?

The app, its config, screen and design APIs

如何安装 @bud.sh/app?

在项目目录运行 npm install @bud.sh/app,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 bud,可以用 npx bud 直接运行。

@bud.sh/app 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@bud.sh/app 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@bud.sh/app 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=26.12.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@bud.sh/app 可以商用吗?

@bud.sh/app 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@bud.sh/app 的下载量有多少?

根据 npm 官方下载统计,@bud.sh/app 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,400 次,日均约 80 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@bud.sh/app 还在维护吗?

最新版本 0.8.1 发布于 2026/11/06(2 天前);至今共发布 12 个版本,其中过去 12 个月发布了 12 个;首次发布于 2026/10/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。