Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ schedules, and there is no read API to save those first. None of these four
declares either. Background services are safe — they are declared in code, so
they re-register on install.

## Two rules that are not obvious
## Three rules that are not obvious

**Every runtime dependency belongs in the plugin's own `package.json`, under
`dependencies`.** bb installs a single subdirectory out of this repository and
Expand All @@ -66,6 +66,21 @@ governs the workspace; the nested ones are what a subdirectory install resolves
against. After changing a plugin's dependencies, regenerate its lock from a copy
of that directory alone, so workspace hoisting does not leak into it.

**A module two plugins share is copied.** A workspace package would not
install, because a plugin installs alone. A published npm package would, but it
runs the same way, because bb bundles each plugin's dependencies into that
plugin. Until something outside this repository needs it, copying one file is
cheaper than a publish pipeline. So `lib/complications.ts` lives in every plugin
that provides or draws a complication, byte for byte. Edit one copy, copy it
over the others, and `npm run check` fails first thing if you forget: the copies
are listed in `scripts/check-vendored.mjs`.

Released copies can still disagree at runtime, because whichever bundle loads
first creates the registry every other plugin uses. Bump
`COMPLICATIONS_IMPLEMENTATION` with any change in its behaviour, fixes included,
so that a newer copy can tell, in the console, when an older one is in charge.
The module's header says what that freezes.

## Releasing

Each plugin releases under its own tag prefix, so a semver range tracks one
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ Four plugins for [bb](https://github.com/get-bb/bb), the agent IDE.
| Plugin | |
| --- | --- |
| **[Follow Up](plugins/follow-up)** | Keeps the work an agent noticed but skipped, so nothing is lost when a turn ends. Triage what a thread accumulated above the composer. |
| **[Thread Badges](plugins/thread-badges)** | Shows pull-request state, CI attention, follow-up progress and listening ports on sidebar rows, so you see what needs you without opening a thread. |
| **[Thread Badges](plugins/thread-badges)** | Shows pull-request state, CI attention, listening ports and badges other plugins publish, like Follow Up's progress, on sidebar rows, so you see what needs you without opening a thread. |
| **[Top Tabs](plugins/top-tabs)** | Opens destinations as tabs across the top of the window, beside a permanent Threads tab, so you can keep several open and switch without losing your place. |
| **[Workflow Stages](plugins/workflow-stages)** | Files every thread under a workflow stage you define, and moves it as the work progresses. Requires the Ribbon sidebar. |

Each is independent. Three soft connections exist and none is required: Thread
Badges draws a follow-up ring when Follow Up is installed and a ports plug when
[Worktree Ports](https://github.com/to-infinity-labs/bb-plugin-worktree-ports)
is, and Workflow Stages needs
Badges draws Follow Up's progress ring once you turn it on, and a ports plug
when [Worktree Ports](https://github.com/to-infinity-labs/bb-plugin-worktree-ports)
is installed, and Workflow Stages needs
[Ribbon sidebar](https://github.com/ariofrio/ribbon) to have anywhere to draw.

## Install
Expand Down
66 changes: 59 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"typecheck": "npm run --workspaces --if-present typecheck",
"test": "npm run --workspaces --if-present test",
"build": "npm run --workspaces --if-present build",
"check": "npm run typecheck && npm run test && npm run build",
"check": "node scripts/check-vendored.mjs && npm run typecheck && npm run test && npm run build",
"bb": "node scripts/bb-dev.mjs",
"plugins": "node scripts/bb-dev.mjs status",
"link": "node scripts/bb-dev.mjs link",
Expand Down
5 changes: 5 additions & 0 deletions plugins/follow-up/PLUGIN_OVERVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ turn, and both are told that "nothing" is a real answer.

## For other plugins

Each thread's progress is published as the `follow-up/progress` complication, a
small value any plugin can draw that is published again the moment a follow-up
changes. Thread Badges draws it as a ring on sidebar rows, once you turn it on
there.

`getFollowUpCountsV1` is a stable, versioned contract: one request returns open
and done counts for up to 500 threads, every requested thread comes back
including ones with nothing recorded, and repeated ids are deduped in
Expand Down
31 changes: 30 additions & 1 deletion plugins/follow-up/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,36 @@ something and want agents to be able to raise it again.

## For other plugins

One method here is a contract rather than an internal call:
Two things here are contracts rather than internal calls: a live value for a
plugin drawing progress, and a batch call for one that only needs to ask.

### The progress complication

Each thread's progress is published as a *complication*: a small value any
plugin can draw, kept in a registry that every plugin bundle in a bb window
shares. [Thread Badges](../thread-badges) 0.4 draws it as a ring that moves the
moment a follow-up changes, once you turn it on under *Badges from other
plugins* in its settings. The counts call below cannot do that, because a plugin
hears only its own realtime signals; this plugin hears `followups-changed`, so
it publishes again on every one.

The registry is protocol v1 of [`lib/complications.ts`](lib/complications.ts),
which a consumer copies into its own plugin; its header is the protocol. Want
`follow-up/progress` for `{ kind: "thread", id }` and the value is:

```ts
{ icon: "TextWrap", label: "27 of 28 follow-ups done", tone: "default",
fraction: 27 / 28, text: "1" } // text: how many are still open
```

`null` for a thread that never recorded a follow-up. Once the list is clear, the
tone is `success` and there is no `text`. Values are published only for threads
a surface wants, and again whenever one of them changes or realtime reconnects.
The provider is registered as long as this plugin's frontend is loaded, so
`isProvided("follow-up/progress")` is how a consumer tells a live Follow Up from
an older one and falls back to the counts call.

### The counts call

```
POST /api/v1/plugins/follow-up/rpc/getFollowUpCountsV1
Expand Down
9 changes: 9 additions & 0 deletions plugins/follow-up/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,17 @@ import { commands } from "./src/commands.ts";
import { FOLLOWUPS_PANEL_ACTION } from "./src/panel-ids.ts";
import { getRpc } from "./src/rpc.ts";
import { toast } from "sonner";
import { ComplicationPublisher } from "./src/complication-publisher.tsx";

export default definePluginApp((app) => {
// Publishes each thread's follow-up progress for any surface drawing it —
// Thread Badges' ring today. An overlay because it must outlive any one
// thread view: it is the only listener for every thread's changes.
app.slots.experimental_appOverlay({
id: "complications",
component: ComplicationPublisher,
});

app.composer.customize({
id: "follow-up",
// "Record the draft" is an alternative to sending it, so it is a row in
Expand Down
Loading
Loading