diff --git a/README.md b/README.md index 5ec94db60..8b2d8eda3 100644 --- a/README.md +++ b/README.md @@ -156,11 +156,7 @@ Install: `bb plugin install git:https://github.com/brsbl/bb-plugins.git@plugin/i Answer everything agents need from you in Waiting on you, a drawer above the prompt box that collects decisions, email replies and plain questions from every thread, urgent first. Track past choices and results in the Decision log. -![Minimal cards](https://github.com/user-attachments/assets/692e0678-252d-47cf-8e1f-01e2b5c3fa7e) - -![Action table and results](https://github.com/user-attachments/assets/ec63ecfe-86ad-4a46-8f6e-06a72e8923f0) - -![Mixed table with one reply expanded](https://github.com/user-attachments/assets/4eef8810-5a99-40af-8fa4-974d25f6937f) +![A sample decision open in Waiting on you, with its context, both options, Recommended and Submit](plugins/inline-action-cards/docs/decision-in-thread.png) [Source](plugins/inline-action-cards) · [README](plugins/inline-action-cards/README.md) diff --git a/plugins/inline-action-cards/README.md b/plugins/inline-action-cards/README.md index a6c59cba3..b65c06de1 100644 --- a/plugins/inline-action-cards/README.md +++ b/plugins/inline-action-cards/README.md @@ -1,8 +1,14 @@ # Inline Decisions -Answer everything agents need from you in one place: **Waiting on you**, a drawer above the prompt box that collects decisions, email replies and plain questions from every thread. +Answer everything agents need from you in one place: **Waiting on you**, a drawer above the prompt box that collects decisions, email replies and plain questions from the active thread. -![Minimal cards](https://github.com/user-attachments/assets/692e0678-252d-47cf-8e1f-01e2b5c3fa7e) +![A sample Workshop plan thread with the decision "Use the garden room for the workshop?" open in Waiting on you, showing its context, both options, Recommended and Submit](docs/decision-in-thread.png) + +![The answered decision settled in the thread: Decision: Use garden room, with the agent's reply](docs/decision-result.png) + +![Waiting on you expanded with two sample asks, the urgent packing checklist question first](docs/waiting-drawer.png) + +![The Decision log with the checklist ask still waiting and the room result plus two dismissed asks in Done](docs/decision-log.png) ## Install diff --git a/plugins/inline-action-cards/app.test.tsx b/plugins/inline-action-cards/app.test.tsx index cdff4aba8..b7baf62ec 100644 --- a/plugins/inline-action-cards/app.test.tsx +++ b/plugins/inline-action-cards/app.test.tsx @@ -487,7 +487,7 @@ it("dismisses a waiting item from the Decision log with a reason, telling its th const reason = screen.getByRole("textbox", { name: "Reason (optional)" }); fireEvent.change(reason, { target: { value: "Paused the campaign" } }); fireEvent.keyDown(reason, { key: "Enter" }); - await waitFor(() => expect(submittedMessages).toEqual(["brsbl dismissed: Raise the ads budget · Paused the campaign"])); + await waitFor(() => expect(submittedMessages).toEqual(["Dismissed: Raise the ads budget · Paused the campaign"])); const saved = JSON.parse((await host.harness.behavior.runCli(["get", "budget", "--thread", "thr_test"])).stdout!); expect(saved).toMatchObject({ state: "succeeded", attempt: null, result: { message: "Dismissed · Paused the campaign" }, dismissed: { reason: "Paused the campaign" } }); const context = JSON.parse((await host.harness.registrations.mentionProviders[0]!.resolve(submittedMentions[0]!.id)).context); diff --git a/plugins/inline-action-cards/docs/decision-in-thread.png b/plugins/inline-action-cards/docs/decision-in-thread.png new file mode 100644 index 000000000..1ce22a949 Binary files /dev/null and b/plugins/inline-action-cards/docs/decision-in-thread.png differ diff --git a/plugins/inline-action-cards/docs/decision-log.png b/plugins/inline-action-cards/docs/decision-log.png new file mode 100644 index 000000000..a9e1d957d Binary files /dev/null and b/plugins/inline-action-cards/docs/decision-log.png differ diff --git a/plugins/inline-action-cards/docs/decision-result.png b/plugins/inline-action-cards/docs/decision-result.png new file mode 100644 index 000000000..614bb9535 Binary files /dev/null and b/plugins/inline-action-cards/docs/decision-result.png differ diff --git a/plugins/inline-action-cards/docs/waiting-drawer.png b/plugins/inline-action-cards/docs/waiting-drawer.png new file mode 100644 index 000000000..16822ede8 Binary files /dev/null and b/plugins/inline-action-cards/docs/waiting-drawer.png differ diff --git a/plugins/inline-action-cards/package.json b/plugins/inline-action-cards/package.json index db765541c..2f0df30c0 100644 --- a/plugins/inline-action-cards/package.json +++ b/plugins/inline-action-cards/package.json @@ -7,6 +7,7 @@ "files": [ "assets", "dist", + "docs", "README.md", "skills" ], diff --git a/plugins/inline-action-cards/server.test.ts b/plugins/inline-action-cards/server.test.ts index b46b808d3..0f73af551 100644 --- a/plugins/inline-action-cards/server.test.ts +++ b/plugins/inline-action-cards/server.test.ts @@ -720,7 +720,7 @@ describe("dismissing", () => { const item = await host.harness.behavior.callRpc("dismiss", { threadId: ref.threadId, id: "channel", revision: 1, reason: "Not needed" }) as Item; expect(item).toMatchObject({ state: "succeeded", attempt: null, result: { message: "Dismissed · Not needed", retryable: false }, dismissed: { reason: "Not needed" } }); expect(host.harness.sdk.callsTo("threads.send")).toHaveLength(1); - expect(host.harness.sdk.callsTo("threads.send")[0]![0]).toMatchObject({ threadId: ref.threadId, input: [{ text: "brsbl dismissed: Which channel · Not needed" }] }); + expect(host.harness.sdk.callsTo("threads.send")[0]![0]).toMatchObject({ threadId: ref.threadId, input: [{ text: "Dismissed: Which channel · Not needed" }] }); expect(await host.harness.behavior.callRpc("waiting", { threadId: ref.threadId })).toEqual([]); const context = JSON.parse((await host.harness.registrations.mentionProviders[0]!.resolve(`${ref.threadId}:channel:dismissed`)).context); expect(context).toMatchObject({ intent: "dismissed", question: "Which channel?", reason: "Not needed" }); @@ -749,7 +749,7 @@ describe("dismissing", () => { await Promise.all(retries); const sends = host.harness.sdk.callsTo("threads.send"); expect(sends).toHaveLength(2); - expect(sends[1]![0]).toMatchObject({ input: [{ text: "brsbl dismissed: Which channel" }] }); + expect(sends[1]![0]).toMatchObject({ input: [{ text: "Dismissed: Which channel" }] }); const settled = await callRpc("notifyDismissed", { threadId: ref.threadId, id: "notice" }) as Item; expect(settled).toMatchObject({ state: "succeeded", attempt: null, dismissed: { notice: "sent" } }); expect(settled.dismissed).not.toHaveProperty("noticeError"); diff --git a/plugins/inline-action-cards/server.ts b/plugins/inline-action-cards/server.ts index 3239927c1..43c34a55c 100644 --- a/plugins/inline-action-cards/server.ts +++ b/plugins/inline-action-cards/server.ts @@ -440,7 +440,7 @@ export default function plugin(bb: BbPluginApi): void { const item = store.claimNotice(threadId, id); if (!item) return store.get(threadId, id); const label = title(item).replace(/[?\s]+$/, ""); - const prefix = "brsbl dismissed: "; + const prefix = "Dismissed: "; const reason = item.dismissed?.reason; try { await bb.sdk.threads.send({ threadId, mode: "queue-if-active", input: [{ diff --git a/plugins/inline-action-cards/skills/inline-action-cards/SKILL.md b/plugins/inline-action-cards/skills/inline-action-cards/SKILL.md index cc0b595c4..d1df2b506 100644 --- a/plugins/inline-action-cards/skills/inline-action-cards/SKILL.md +++ b/plugins/inline-action-cards/skills/inline-action-cards/SKILL.md @@ -58,7 +58,7 @@ If a card needs more than that, the decision is too big: split it, or, when the Bad cards: -- “Run the code review on the Live Markdown stack?” A routine step; just do it. +- “Run the code review on the sample change?” A routine step; just do it. - “Approve the claim lines on the comparison page?” It needs a careful read, so ask for a review instead. - “Cancel the stray trial yourself, then reply done.” An agent with browser access can do it. - “Unlist the theme after the takedown request?” when the user has never heard of the request. @@ -66,7 +66,7 @@ Bad cards: - “Move the trip two days later?” with no fares for either option and the wrong number of travelers. - “Approve?” with a five-bullet What/Why now/Options/Recommendation/Next brief: busy, and the user doesn't read it. -**Good:** “Merge the Live Markdown stack?” once its required checks pass; labels “Merge both PRs” / “Keep them open”; `recommended: "yes"`; context “[Checks and review](https://example.com/checks) passed on the final heads.” +**Good (fictional example):** question “Use the Moonbase Garden Club’s draft as the planting plan?”; labels “Use this plan” / “Revise it first”; `recommended: "yes"`; context “The club needs the plan by Friday.” Every example in this skill is illustrative. Use verified facts, include the exact head when approval depends on a revision, and never claim a gate passed because an example says so.