Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar | 1 | import { test } from "node:test"; |
| 2 | import assert from "node:assert/strict"; | |
| 3 | ||
| 4 | import { cleanCard } from "./cards.ts"; | |
| 5 | ||
| 6 | test("a card needs a kind and a title", () => { | |
| 7 | assert.equal(cleanCard(null), null); | |
| 8 | assert.equal(cleanCard("card"), null); | |
| 9 | assert.equal(cleanCard({ kind: "session" }), null); | |
| 10 | assert.equal(cleanCard({ title: "Fix the login" }), null); | |
| 11 | assert.deepEqual(cleanCard({ kind: " session ", title: " Fix the login " }), { | |
| 12 | kind: "session", | |
| 13 | title: "Fix the login", | |
| 14 | detail: null, | |
| 15 | state: null, | |
| 16 | href: null, | |
| 17 | }); | |
| 18 | }); | |
| 19 | ||
| 20 | test("links stay on the site", () => { | |
| 21 | assert.equal(cleanCard({ kind: "pull", title: "x", href: "/acme/web/pull/1" })?.href, "/acme/web/pull/1"); | |
| 22 | assert.equal(cleanCard({ kind: "pull", title: "x", href: "https://evil.example" })?.href, null); | |
| 23 | assert.equal(cleanCard({ kind: "pull", title: "x", href: "//evil.example" })?.href, null); | |
| 24 | }); | |
| 25 | ||
| 26 | test("fields keep labelled values and drop the rest", () => { | |
| 27 | const card = cleanCard({ | |
| 28 | kind: "draft_issue", | |
| 29 | title: "x", | |
| 30 | fields: [{ label: "Repository", value: "acme/web" }, { label: "Labels" }, { value: "orphan" }, "nope", null, { label: " ", value: "x" }], | |
| 31 | }); | |
| 32 | assert.deepEqual(card?.fields, [{ label: "Repository", value: "acme/web" }]); | |
| 33 | assert.equal(cleanCard({ kind: "x", title: "x", fields: [] })?.fields, undefined); | |
| 34 | const many = Array.from({ length: 12 }, (_, i) => ({ label: `L${i}`, value: "v" })); | |
| 35 | assert.equal(cleanCard({ kind: "x", title: "x", fields: many })?.fields?.length, 8); | |
| 36 | }); | |
| 37 | ||
| 38 | test("actions keep valid ones, normalised, and drop invalid ones and outside links", () => { | |
| 39 | const card = cleanCard({ | |
| 40 | kind: "session", | |
| 41 | title: "x", | |
| 42 | owner: "agents", | |
| 43 | ref: "ses_1", | |
| 44 | actions: [ | |
| 45 | { id: "approve", label: "Approve more", style: "primary", input: { kind: "money", label: "Amount", initial: "2.00" } }, | |
| 46 | { id: "stop", label: "Stop", style: "danger", confirm: "Stop this session?" }, | |
| 47 | { id: "message", label: "Message", style: "loud", input: { kind: "voice", label: "x" } }, | |
| 48 | { id: "Bad Id", label: "x" }, | |
| 49 | { id: "nolabel" }, | |
| 50 | { id: "open", label: "Open", href: "https://elsewhere.example" }, | |
| 51 | "nope", | |
| 52 | ], | |
| 53 | }); | |
| 54 | assert.equal(card?.owner, "agents"); | |
| 55 | assert.equal(card?.ref, "ses_1"); | |
| 56 | assert.deepEqual(card?.actions, [ | |
| 57 | { id: "approve", label: "Approve more", style: "primary", confirm: null, input: { kind: "money", label: "Amount", placeholder: null, initial: "2.00" }, href: null }, | |
| 58 | { id: "stop", label: "Stop", style: "danger", confirm: "Stop this session?", input: null, href: null }, | |
| 59 | { id: "message", label: "Message", style: "default", confirm: null, input: null, href: null }, | |
| 60 | ]); | |
| 61 | }); | |
| 62 | ||
| 63 | test("without an owner only link actions are kept", () => { | |
| 64 | const card = cleanCard({ | |
| 65 | kind: "pull", | |
| 66 | title: "x", | |
| 67 | owner: "github", | |
| 68 | actions: [ | |
| 69 | { id: "merge", label: "Merge", style: "primary" }, | |
| 70 | { id: "open", label: "Open", href: "/acme/web/pull/1" }, | |
| 71 | ], | |
| 72 | }); | |
| 73 | assert.equal(card?.owner, undefined); | |
| 74 | assert.equal(card?.ref, undefined); | |
| 75 | assert.deepEqual(card?.actions, [{ id: "open", label: "Open", style: "default", confirm: null, input: null, href: "/acme/web/pull/1" }]); | |
| 76 | }); | |
| 77 | ||
| 78 | test("a card offers at most five actions", () => { | |
| 79 | const actions = Array.from({ length: 9 }, (_, i) => ({ id: `a${i}`, label: `A${i}` })); | |
| 80 | assert.equal(cleanCard({ kind: "x", title: "x", owner: "agents", actions })?.actions?.length, 5); | |
| 81 | }); |