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.
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; | |
| 3 | ||
| 4 | import type { AgentSession, InboxItem } from "@g1t/contracts"; | |
| 5 | ||
| 6 | import { | |
| 7 | type AttentionRow, | |
| 8 | type CodeNeed, | |
| 9 | type CodePull, | |
| 10 | acceptance, | |
| 11 | agentRow, | |
| 12 | attention, | |
| 13 | chatRow, | |
| 14 | codeRow, | |
| 15 | dayIn, | |
| 16 | daySentence, | |
| 17 | dayWork, | |
| 18 | daysBefore, | |
| 19 | notificationRow, | |
| 20 | pullOutcome, | |
| 21 | rankAttention, | |
| 22 | sessionOutcome, | |
| 23 | spendToday, | |
| 24 | startHere, | |
| 25 | trendLabel, | |
| 26 | waitingSentence, | |
| 27 | } from "./today.ts"; | |
| 28 | ||
| 29 | const HOUR = 3_600_000; | |
| 30 | const DAY = 24 * HOUR; | |
| 31 | // Friday 2026-10-09, 18:00 UTC; 11:00 in Los Angeles. | |
| 32 | const NOW = Date.parse("2026-10-09T18:00:00Z"); | |
| 33 | const LA = "America/Los_Angeles"; | |
| 34 | const repo = { namespace: "acme", name: "web" }; | |
| 35 | const iso = (ms: number) => new Date(ms).toISOString(); | |
| 36 | ||
| 37 | function pull(over: Partial<CodePull> = {}): CodePull { | |
| 38 | return { | |
| 39 | repo, | |
| 40 | number: 1, | |
| 41 | title: "Fix the flaky test", | |
| 42 | status: "merged", | |
| 43 | mergedAt: iso(NOW - HOUR), | |
| 44 | createdAt: iso(NOW - 3 * HOUR), | |
| 45 | updatedAt: iso(NOW - HOUR), | |
| 46 | author: { username: "g1t", kind: "agent" }, | |
| 47 | ...over, | |
| 48 | }; | |
| 49 | } | |
| 50 | ||
| 51 | function session(over: Partial<AgentSession> = {}): AgentSession { | |
| 52 | return { | |
| 53 | id: "s1", | |
| 54 | workspace_id: "w", | |
| 55 | agent_id: "a", | |
| 56 | agent_handle: "margo", | |
| 57 | agent_name: "Margo", | |
| 58 | agent_avatar_seed: "margo", | |
| 59 | subagent: null, | |
| 60 | kind: "chat", | |
| 61 | parent_id: null, | |
| 62 | root_id: "s1", | |
| 63 | payer_agent_id: "a", | |
| 64 | title: "Draft the launch notes", | |
| 65 | goal: "", | |
| 66 | status: "done", | |
| 67 | status_note: null, | |
| 68 | summary: null, | |
| 69 | channel_id: "c", | |
| 70 | channel_kind: "channel", | |
| 71 | channel_name: "launch", | |
| 72 | card_message_id: null, | |
| 73 | asked_by: null, | |
| 74 | asked_by_username: "bo", | |
| 75 | routine_id: null, | |
| 76 | steps: 3, | |
| 77 | tool_calls: 2, | |
| 78 | input_tokens: 0, | |
| 79 | output_tokens: 0, | |
| 80 | charged_micros: 400_000, | |
| 81 | cap_micros: 2_000_000, | |
| 82 | model: null, | |
| 83 | outputs: [], | |
| 84 | created_at: iso(NOW - 2 * HOUR), | |
| 85 | updated_at: iso(NOW - HOUR), | |
| 86 | finished_at: iso(NOW - HOUR), | |
| 87 | visible: true, | |
| 88 | ...over, | |
| 89 | }; | |
| 90 | } | |
| 91 | ||
| 92 | test("today is the reader's day, and the seven days before it", () => { | |
| 93 | assert.equal(dayIn(NOW, LA), "2026-10-09"); | |
| 94 | assert.equal(dayIn(Date.parse("2026-10-10T02:00:00Z"), LA), "2026-10-09"); | |
| 95 | assert.equal(dayIn(Date.parse("2026-10-10T02:00:00Z"), null), "2026-10-10"); | |
| 96 | assert.equal(dayIn(NOW, "Not/AZone"), "2026-10-09"); | |
| 97 | assert.deepEqual(daysBefore(NOW, LA, 3), ["2026-10-08", "2026-10-07", "2026-10-06"]); | |
| 98 | }); | |
| 99 | ||
| 100 | test("an agent's pull request is accepted first time when it merged today with no revision", () => { | |
| 101 | assert.equal(pullOutcome(pull(), 0, "2026-10-09", null), "accepted"); | |
| 102 | assert.equal(pullOutcome(pull(), 2, "2026-10-09", null), "fixed"); | |
| 103 | assert.equal(pullOutcome(pull({ mergedAt: iso(NOW - DAY) }), 0, "2026-10-09", null), null); | |
| 104 | assert.equal(pullOutcome(pull({ status: "closed", mergedAt: null }), 0, "2026-10-09", null), "dropped"); | |
| 105 | assert.equal(pullOutcome(pull({ status: "open", mergedAt: null }), 1, "2026-10-09", null), "open"); | |
| 106 | assert.equal(pullOutcome(pull({ status: "draft", mergedAt: null, updatedAt: iso(NOW - 2 * DAY) }), 0, "2026-10-09", null), null); | |
| 107 | }); | |
| 108 | ||
| 109 | test("a session counts once, at the root of its tree, and is never 'accepted'", () => { | |
| 110 | assert.equal(sessionOutcome(session(), "2026-10-09", null), "finished"); | |
| 111 | assert.equal(sessionOutcome(session({ parent_id: "s0" }), "2026-10-09", null), null); | |
| 112 | assert.equal(sessionOutcome(session({ status: "failed" }), "2026-10-09", null), "dropped"); | |
| 113 | assert.equal(sessionOutcome(session({ status: "stopped" }), "2026-10-09", null), "dropped"); | |
| 114 | assert.equal(sessionOutcome(session({ status: "working", finished_at: null }), "2026-10-09", null), "open"); | |
| 115 | assert.equal(sessionOutcome(session({ status: "needs_approval", finished_at: null, updated_at: iso(NOW - 3 * DAY) }), "2026-10-09", null), null); | |
| 116 | assert.equal(sessionOutcome(session({ finished_at: iso(NOW - DAY) }), "2026-10-09", null), null); | |
| 117 | }); | |
| 118 | ||
| 119 | test("accepted first time is accepted over every agent pull request that settled", () => { | |
| 120 | assert.deepEqual(acceptance(["accepted", "accepted", "fixed", "dropped", "open", "finished"]), { value: 0.5, of: 4 }); | |
| 121 | assert.equal(acceptance(["open", "finished"]), null); | |
| 122 | }); | |
| 123 | ||
| 124 | test("the day's work: pull requests and sessions, sources, and the week before", () => { | |
| 125 | const work = dayWork({ | |
| 126 | now: NOW, | |
| 127 | timeZone: null, | |
| 128 | slug: "acme", | |
| 129 | code: { | |
| 130 | pulls: [ | |
| 131 | pull({ number: 1 }), | |
| 132 | pull({ number: 2 }), | |
| 133 | pull({ number: 3, status: "open", mergedAt: null }), | |
| 134 | // A person's pull request is not agent work. | |
| 135 | pull({ number: 4, author: { username: "bo", kind: "user" } }), | |
| 136 | // The week before: one accepted, one fixed. | |
| 137 | pull({ number: 5, mergedAt: iso(NOW - 2 * DAY), updatedAt: iso(NOW - 2 * DAY) }), | |
| 138 | pull({ number: 6, mergedAt: iso(NOW - 3 * DAY), updatedAt: iso(NOW - 3 * DAY) }), | |
| 139 | // Older than a week: not counted. | |
| 140 | pull({ number: 7, mergedAt: iso(NOW - 9 * DAY), updatedAt: iso(NOW - 9 * DAY) }), | |
| 141 | ], | |
| 142 | revisions: { "acme/web#2": 1, "acme/web#6": 2 }, | |
| 143 | complete: true, | |
| 144 | }, | |
| 145 | sessions: { sessions: [session(), session({ id: "s2", kind: "routine", status: "working", finished_at: null }), session({ id: "s3", parent_id: "s1" })], complete: true }, | |
| 146 | }); | |
| 147 | assert.equal(work.tasks.length, 5); | |
| 148 | assert.deepEqual(work.counts, { accepted: 1, fixed: 1, finished: 1, open: 2, dropped: 0 }); | |
| 149 | assert.deepEqual(work.rate, { value: 0.5, of: 2 }); | |
| 150 | assert.deepEqual(work.lastWeek, { value: 0.5, of: 2 }); | |
| 151 | assert.deepEqual(work.sources, [ | |
| 152 | { source: "code", count: 3 }, | |
| 153 | { source: "chat", count: 1 }, | |
| 154 | { source: "schedule", count: 1 }, | |
| 155 | ]); | |
| 156 | // Open work goes last on the strip. | |
| 157 | assert.deepEqual(work.tasks.slice(-2).map((t) => t.outcome), ["open", "open"]); | |
| 158 | assert.equal(work.code, "read"); | |
| 159 | assert.equal(work.partial, false); | |
| 160 | assert.equal(daySentence(work), "Agents finished 3 tasks. 1 needed a fix after review, and 2 are still open."); | |
| 161 | }); | |
| 162 | ||
| 163 | test("no trend when the week could not all be read, and none without Code", () => { | |
| 164 | const partial = dayWork({ now: NOW, timeZone: null, slug: "acme", code: { pulls: [pull()], revisions: {}, complete: false }, sessions: null }); | |
| 165 | assert.equal(partial.lastWeek, null); | |
| 166 | assert.equal(partial.partial, true); | |
| 167 | assert.equal(partial.sessions, "unavailable"); | |
| 168 | const member = dayWork({ now: NOW, timeZone: null, slug: "acme", code: "no_access", sessions: { sessions: [session()], complete: true } }); | |
| 169 | assert.equal(member.code, "no_access"); | |
| 170 | assert.equal(member.rate, null); | |
| 171 | assert.equal(member.tasks.every((t) => t.source !== "code"), true); | |
| 172 | }); | |
| 173 | ||
| 174 | test("the trend is in whole points", () => { | |
| 175 | assert.equal(trendLabel({ value: 0.89 }, { value: 0.83 }), "+6 pts vs the last 7 days"); | |
| 176 | assert.equal(trendLabel({ value: 0.5 }, { value: 0.75 }), "−25 pts vs the last 7 days"); | |
| 177 | assert.equal(trendLabel({ value: 0.5 }, { value: 0.5 }), "Same as the last 7 days"); | |
| 178 | assert.equal(trendLabel(null, { value: 0.5 }), null); | |
| 179 | }); | |
| 180 | ||
| 181 | test("the sentence for a quiet day, and for what waits", () => { | |
| 182 | const quiet = dayWork({ now: NOW, timeZone: null, slug: "acme", code: { pulls: [], revisions: {}, complete: true }, sessions: { sessions: [], complete: true } }); | |
| 183 | assert.equal(daySentence(quiet), "No agent work today yet."); | |
| 184 | assert.equal(waitingSentence(0), "Nothing is waiting on you."); | |
| 185 | assert.equal(waitingSentence(1), "1 thing is waiting on you."); | |
| 186 | assert.equal(waitingSentence(8), "8 things are waiting on you."); | |
| 187 | }); | |
| 188 | ||
| 189 | const need = (over: Partial<CodeNeed>): CodeNeed => ({ | |
| 190 | key: "pull:p1", | |
| 191 | reason: "ready_to_merge", | |
| 192 | repo, | |
| 193 | ref: "#12", | |
| 194 | title: "Add retries", | |
| 195 | ask: "Waiting for you to merge it.", | |
| 196 | by: { name: "g1t", agent: true }, | |
| 197 | for: "bo", | |
| 198 | at: NOW - 2 * HOUR, | |
| 199 | to: "/acme/web/pull/12", | |
| 200 | facts: [{ label: "Files changed", value: "4", tone: null }], | |
| 201 | ...over, | |
| 202 | }); | |
| 203 | ||
| 204 | test("Code's needs become rows with what is at stake", () => { | |
| 205 | const ready = codeRow(need({})); | |
| 206 | assert.equal(ready.kind, "ready"); | |
| 207 | assert.equal(ready.stake?.text, "4 files to land"); | |
| 208 | assert.equal(ready.action.label, "Merge"); | |
| 209 | const deploy = codeRow(need({ key: "deploy:site", reason: "blocking", facts: [{ label: "Production", value: "Serving the build before", tone: "good" }] })); | |
| 210 | assert.equal(deploy.kind, "deploy"); | |
| 211 | assert.equal(deploy.stake?.text, "Production on an older build"); | |
| 212 | assert.equal(codeRow(need({ reason: "checks_failing" })).kind, "pull_blocked"); | |
| 213 | assert.equal(codeRow(need({ key: "run:r1", reason: "stalled", facts: [{ label: "Cost so far", value: "$1.20", tone: null }] })).stake?.text, "$1.20 so far"); | |
| 214 | }); | |
| 215 | ||
| 216 | const row = (over: Partial<AttentionRow>): AttentionRow => ({ | |
| 217 | key: "k", | |
| 218 | kind: "chat", | |
| 219 | title: "t", | |
| 220 | detail: "d", | |
| 221 | stake: null, | |
| 222 | action: { label: "Open", to: "/x" }, | |
| 223 | owner: null, | |
| 224 | at: NOW, | |
| 225 | from: "chat", | |
| 226 | ...over, | |
| 227 | }); | |
| 228 | ||
| 229 | test("Start here: the most pressing tier first, then what has waited longest", () => { | |
| 230 | const rows = [ | |
| 231 | row({ key: "chat:old", kind: "chat", at: NOW - 5 * DAY, action: { label: "Reply", to: "/acme/-/chat/general" } }), | |
| 232 | row({ key: "ready:new", kind: "ready", at: NOW - HOUR, action: { label: "Merge", to: "/acme/web/pull/2" } }), | |
| 233 | row({ key: "ready:old", kind: "ready", at: NOW - 3 * HOUR, action: { label: "Merge", to: "/acme/web/pull/1" } }), | |
| 234 | row({ key: "session:s", kind: "session_cap", at: NOW - 10 * 60_000, action: { label: "Approve more", to: "/acme/-/agents/margo/sessions/s" } }), | |
| 235 | ]; | |
| 236 | const ranked = rankAttention(rows); | |
| 237 | assert.deepEqual(ranked.map((r) => r.key), ["session:s", "ready:old", "ready:new", "chat:old"]); | |
| 238 | const start = startHere(ranked); | |
| 239 | assert.equal(start?.row.key, "session:s"); | |
| 240 | assert.match(start?.why ?? "", /spend cap/); | |
| 241 | // A failed production deploy beats everything. | |
| 242 | const withDeploy = rankAttention([...rows, row({ key: "deploy:site", kind: "deploy", at: NOW, action: { label: "See the build", to: "/acme/site/deployments/1" } })]); | |
| 243 | assert.equal(startHere(withDeploy)?.row.key, "deploy:site"); | |
| 244 | // Ties in tier say so. | |
| 245 | const two = startHere(rankAttention(rows.filter((r) => r.kind === "ready"))); | |
| 246 | assert.equal(two?.row.key, "ready:old"); | |
| 247 | assert.match(two?.why ?? "", /Of the 2 like it, it has waited longest/); | |
| 248 | assert.equal(startHere([]), null); | |
| 249 | }); | |
| 250 | ||
| 251 | test("the same order whatever order the rows came in", () => { | |
| 252 | const rows = [row({ key: "b", kind: "review", at: NOW }), row({ key: "a", kind: "review", at: NOW, action: { label: "Review", to: "/y" } })]; | |
| 253 | assert.deepEqual(rankAttention(rows).map((r) => r.key), ["a", "b"]); | |
| 254 | assert.deepEqual(rankAttention([...rows].reverse()).map((r) => r.key), ["a", "b"]); | |
| 255 | }); | |
| 256 | ||
| 257 | const item = (over: Partial<InboxItem>): InboxItem => ({ | |
| 258 | id: "n1", | |
| 259 | reason: "ci_activity", | |
| 260 | severity: "error", | |
| 261 | title: "Checks failed on #12", | |
| 262 | body: "Add retries", | |
| 263 | event: "check.failed", | |
| 264 | repo: "acme/web", | |
| 265 | workspace: "acme", | |
| 266 | subject: "pull", | |
| 267 | number: 12, | |
| 268 | url: "/acme/web/pull/12", | |
| 269 | actor: "g1t", | |
| 270 | count: 1, | |
| 271 | createdAt: iso(NOW - HOUR), | |
| 272 | updatedAt: iso(NOW - HOUR), | |
| 273 | readAt: null, | |
| 274 | doneAt: null, | |
| 275 | saved: false, | |
| 276 | snoozedUntil: null, | |
| 277 | ...over, | |
| 278 | }); | |
| 279 | ||
| 280 | test("notifications: warnings and failures in this workspace; none about repositories without Code", () => { | |
| 281 | assert.equal(notificationRow(item({}), "acme", true)?.kind, "notification"); | |
| 282 | assert.equal(notificationRow(item({}), "acme", false), null); | |
| 283 | assert.equal(notificationRow(item({ repo: null, url: "/acme/-/agents/margo" }), "acme", false)?.kind, "notification"); | |
| 284 | assert.equal(notificationRow(item({ severity: "info" }), "acme", true), null); | |
| 285 | assert.equal(notificationRow(item({ workspace: "other", repo: "other/web" }), "acme", true), null); | |
| 286 | assert.equal(notificationRow(item({ readAt: iso(NOW) }), "acme", true), null); | |
| 287 | }); | |
| 288 | ||
| 289 | test("a notification about something already listed is left out", () => { | |
| 290 | const out = attention({ | |
| 291 | slug: "acme", | |
| 292 | code: true, | |
| 293 | codeNeeds: [need({})], | |
| 294 | capped: [], | |
| 295 | agents: [], | |
| 296 | canManage: false, | |
| 297 | notifications: [item({})], | |
| 298 | chat: [], | |
| 299 | }); | |
| 300 | assert.deepEqual(out.rows.map((r) => r.key), ["pull:p1"]); | |
| 301 | assert.deepEqual(out.missing, []); | |
| 302 | }); | |
| 303 | ||
| 304 | test("without Code access no Code row is asked for or shown, and a silent source is named", () => { | |
| 305 | const out = attention({ | |
| 306 | slug: "acme", | |
| 307 | code: false, | |
| 308 | codeNeeds: [need({})], | |
| 309 | capped: null, | |
| 310 | agents: null, | |
| 311 | canManage: false, | |
| 312 | notifications: [item({}), item({ id: "n2", repo: null, reason: "agent", severity: "warning", url: "/acme/-/agents/margo" })], | |
| 313 | chat: null, | |
| 314 | }); | |
| 315 | assert.deepEqual(out.rows.map((r) => r.key), ["notification:n2"]); | |
| 316 | assert.equal(out.rows.some((r) => r.from === "code"), false); | |
| 317 | assert.deepEqual(out.missing, ["Agents", "Chat"]); | |
| 318 | }); | |
| 319 | ||
| 320 | test("an agent out of budget is listed only for those who may raise it", () => { | |
| 321 | const agent = { id: "a1", handle: "margo", display_name: "Margo", status: "out_of_budget", spent_month_micros: 52_000_000, budget: { monthly_micros: 50_000_000 }, updated_at: iso(NOW) }; | |
| 322 | assert.equal(agentRow(agent, "acme")?.stake?.text, "$0.00 left"); | |
| 323 | const base = { slug: "acme", code: true, codeNeeds: [], capped: [], notifications: [], chat: [] }; | |
| 324 | assert.equal(attention({ ...base, agents: [agent], canManage: false }).rows.length, 0); | |
| 325 | assert.equal(attention({ ...base, agents: [agent], canManage: true }).rows[0]?.kind, "agent_budget"); | |
| 326 | }); | |
| 327 | ||
| 328 | test("chat: mentions anywhere and unread direct messages, never muted", () => { | |
| 329 | const channel = { id: "c1", kind: "channel" as const, name: "general", last_message_at: iso(NOW) }; | |
| 330 | assert.equal(chatRow({ channel, title: "general", muted: false, unread: 4, mentions: 0 }, "acme"), null); | |
| 331 | assert.equal(chatRow({ channel, title: "general", muted: false, unread: 4, mentions: 2 }, "acme")?.stake?.text, "2 mentions"); | |
| 332 | assert.equal(chatRow({ channel, title: "general", muted: true, unread: 4, mentions: 2 }, "acme"), null); | |
| 333 | const dm = chatRow({ channel: { ...channel, kind: "dm", name: null }, title: "Bo Reed", muted: false, unread: 1, mentions: 0 }, "acme"); | |
| 334 | assert.equal(dm?.action.to, "/acme/-/chat/dm/c1"); | |
| 335 | }); | |
| 336 | ||
| 337 | test("spent today: today's UTC group of the statement, at price, without money in", () => { | |
| 338 | const spend = spendToday( | |
| 339 | { | |
| 340 | groups: [ | |
| 341 | { | |
| 342 | key: "2026-10-09", | |
| 343 | label: "2026-10-09", | |
| 344 | chargedMicros: 0, | |
| 345 | lines: [ | |
| 346 | { kind: "Agent runs", count: 12, chargedMicros: 3_000_000, costMicros: 2_500_000, priceMicros: 4_000_000 }, | |
| 347 | { kind: "Sandbox time", count: 12, chargedMicros: 600_000, costMicros: 500_000 }, | |
| 348 | { kind: "Payments", count: 1, chargedMicros: -50_000_000, costMicros: 0, priceMicros: 0 }, | |
| 349 | ], | |
| 350 | }, | |
| 351 | { key: "2026-10-08", label: "2026-10-08", chargedMicros: 0, lines: [{ kind: "Agent runs", count: 3, chargedMicros: 9_000_000, costMicros: 0 }] }, | |
| 352 | ], | |
| 353 | totals: { chargedMicros: 12_600_000, paidMicros: 50_000_000, costMicros: 0, entries: 4, priceMicros: 13_600_000 }, | |
| 354 | }, | |
| 355 | NOW, | |
| 356 | ); | |
| 357 | assert.equal(spend.day, "2026-10-09"); | |
| 358 | assert.equal(spend.totalMicros, 4_600_000); | |
| 359 | assert.deepEqual(spend.lines.map((l) => l.kind), ["Agent runs", "Sandbox time"]); | |
| 360 | assert.equal(spend.monthMicros, 13_600_000); | |
| 361 | }); |