diff --git a/.lane/memory/apps/app/src/app.tsx/01M4YT6XB7NQ89E6F4P375REE7-all-projects-and-project-vie.md b/.lane/memory/apps/app/src/app.tsx/01M4YT6XB7NQ89E6F4P375REE7-all-projects-and-project-vie.md index bd92d446..0be2d0cd 100644 --- a/.lane/memory/apps/app/src/app.tsx/01M4YT6XB7NQ89E6F4P375REE7-all-projects-and-project-vie.md +++ b/.lane/memory/apps/app/src/app.tsx/01M4YT6XB7NQ89E6F4P375REE7-all-projects-and-project-vie.md @@ -4,9 +4,9 @@ anchor: function App created: 2026-10-15T03:38:04Z norm: '1' sig: 063d0f00fea02511 -body_hash: fe9a115489fd2e3a -raw_hash: 4c1a930753d49cc2 -vouched: 2026-10-23T14:00:31Z +body_hash: d83ccb35867e607a +raw_hash: 90ddf2e883ff2d5c +vouched: 2026-10-23T14:03:54Z lines: 235-824 --- diff --git a/.lane/memory/apps/app/src/app.tsx/01M5AYXP2WM5WYKYA2RC58AAYC-each-capability-mirrors-a-ho.md b/.lane/memory/apps/app/src/app.tsx/01M5AYXP2WM5WYKYA2RC58AAYC-each-capability-mirrors-a-ho.md index b337f86f..483b4b17 100644 --- a/.lane/memory/apps/app/src/app.tsx/01M5AYXP2WM5WYKYA2RC58AAYC-each-capability-mirrors-a-ho.md +++ b/.lane/memory/apps/app/src/app.tsx/01M5AYXP2WM5WYKYA2RC58AAYC-each-capability-mirrors-a-ho.md @@ -4,9 +4,9 @@ anchor: function row created: 2026-10-19T20:51:09Z norm: '1' sig: 3ee93dbf7c44f79a -body_hash: 8365145a4d0f53de -raw_hash: c6795856e4c91aa5 -vouched: 2026-10-22T14:47:34Z +body_hash: 2b37c0b054a09374 +raw_hash: e19d804ba1eb0f23 +vouched: 2026-10-23T14:03:22Z lines: 120-170 --- diff --git a/.lane/memory/apps/app/src/app.tsx/01M5JMVG9G87F31FGVV571Y6BJ-the-project-list-is-built-on.md b/.lane/memory/apps/app/src/app.tsx/01M5JMVG9G87F31FGVV571Y6BJ-the-project-list-is-built-on.md index 082d6017..4f75ec4e 100644 --- a/.lane/memory/apps/app/src/app.tsx/01M5JMVG9G87F31FGVV571Y6BJ-the-project-list-is-built-on.md +++ b/.lane/memory/apps/app/src/app.tsx/01M5JMVG9G87F31FGVV571Y6BJ-the-project-list-is-built-on.md @@ -4,9 +4,9 @@ anchor: function App created: 2026-10-22T20:29:16Z norm: '1' sig: 063d0f00fea02511 -body_hash: fe9a115489fd2e3a -raw_hash: 4c1a930753d49cc2 -vouched: 2026-10-23T14:00:32Z +body_hash: d83ccb35867e607a +raw_hash: 90ddf2e883ff2d5c +vouched: 2026-10-23T14:03:54Z lines: 330-1237 --- diff --git a/.lane/memory/apps/app/src/app.tsx/01M5MH5GTCT454K45QT5RJE1H5-only-a-window-that-never-cho.md b/.lane/memory/apps/app/src/app.tsx/01M5MH5GTCT454K45QT5RJE1H5-only-a-window-that-never-cho.md new file mode 100644 index 00000000..d8fd1338 --- /dev/null +++ b/.lane/memory/apps/app/src/app.tsx/01M5MH5GTCT454K45QT5RJE1H5-only-a-window-that-never-cho.md @@ -0,0 +1,13 @@ +--- +id: 01M5MH5GTCT454K45QT5RJE1H5 +anchor: function App +created: 2026-10-23T14:03:19Z +norm: '1' +sig: 063d0f00fea02511 +body_hash: d83ccb35867e607a +raw_hash: 90ddf2e883ff2d5c +vouched: 2026-10-23T14:03:54Z +lines: 334-1357 +--- + +only a window that never chose a project jumps to a run that needs you, once; a saved project or channel always wins diff --git a/apps/app/src/app.tsx b/apps/app/src/app.tsx index 1ed99bea..f71ea593 100644 --- a/apps/app/src/app.tsx +++ b/apps/app/src/app.tsx @@ -229,7 +229,7 @@ function row( ? "thinking" : "idle", unreadCount: outcome === "done" || outcome === "message" ? 1 : 0, - needsAttention: outcome === "failed" || outcome === "question", + needsAttention: outcome === "failed" || outcome === "question" ? outcome : undefined, mentionCount: attention?.mentions || 0, lastActivityAt: Math.floor((channel.active || channel.created) / 1000), online, @@ -531,6 +531,19 @@ export function App() { page === "channels" ? channel?.id : undefined, people, ); + // A window that never chose a project, such as one a sign-in link opened, starts at a run that + // needs you instead of the first project's Dashboard. + const landed = useRef(false); + useEffect(() => { + if (landed.current || project !== undefined || !hello.host) return; + const waiting = channels.find((value) => { + const mark = attention.get(value.id)?.mark; + return mark === "question" || mark === "failed"; + }); + if (!waiting) return; + landed.current = true; + select(waiting); + }); const online = (channel: Listing) => present(presence[channelProject(channel)], people[hello.user], channel.id); let groups = projectGroups(visible, hello, people, now, collapsed, attention, pins, online); diff --git a/apps/app/src/dashboard.tsx b/apps/app/src/dashboard.tsx index 21b239c9..c4920ee2 100644 --- a/apps/app/src/dashboard.tsx +++ b/apps/app/src/dashboard.tsx @@ -269,6 +269,11 @@ function TeammateRow({ teammate, onChannel }: { ); } +const NEEDS = { + failed: "Needs you: a run you started failed", + question: "Needs you: the agent is waiting for your answer", +}; + /** The sidebar row's marks: a raised hand for a run that needs you, mentions, then unread. */ function Marks({ attention }: { attention?: Attention }) { if (!attention) return null; @@ -276,7 +281,14 @@ function Marks({ attention }: { attention?: Attention }) { return ( {(mark === "failed" || mark === "question") && ( - + + } + > + + + {NEEDS[mark]} + )} {mentions > 0 && ( - span:first-child]:grid [&>span:first-child]:size-4.5 [&>span:first-child]:place-items-center", - )} + + + } > - - - + span:first-child]:grid [&>span:first-child]:size-4.5 [&>span:first-child]:place-items-center", + )} + > + + + + + {label} + + ); } @@ -156,10 +166,16 @@ function mentionText(count: number) { return `${count} direct ${count === 1 ? "mention" : "mentions"}`; } +const NEEDS = { + failed: "a run you started failed", + question: "the agent is waiting for your answer", +}; + function attentionText(data: SidebarRow, showAttention: boolean) { - if (!showAttention) return mentionText(data.mentionCount); - if (data.mentionCount <= 0) return "Agent needs your attention"; - return `${mentionText(data.mentionCount)} and agent needs your attention`; + if (!showAttention || !data.needsAttention) return mentionText(data.mentionCount); + const reason = `Needs you: ${NEEDS[data.needsAttention]}`; + if (data.mentionCount <= 0) return reason; + return `${reason}, and ${mentionText(data.mentionCount)}`; } function canShowMention({ diff --git a/packages/ui/src/components/session-item/session-item.types.ts b/packages/ui/src/components/session-item/session-item.types.ts index 39eb6646..15b53584 100644 --- a/packages/ui/src/components/session-item/session-item.types.ts +++ b/packages/ui/src/components/session-item/session-item.types.ts @@ -66,7 +66,8 @@ export type SidebarRow = { // Conversation (viewer-relative) unreadCount: number; mentionCount: number; - needsAttention?: boolean; + /** Why the row needs the viewer: a run they started failed or waits on their answer. */ + needsAttention?: "failed" | "question"; lastSpeaker?: "user" | "agent"; lastActivityAt: UNIX;