Skip to content
Merged

sdf #52

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
287394f
fix manual computer use toggle off
snowdamiz May 31, 2026
4957970
save
snowdamiz Jun 1, 2026
b47a9a1
fixes
snowdamiz Jun 1, 2026
0a9c94b
Inject current date into agent prompts
snowdamiz Jun 1, 2026
c23c33d
Persist terminal tabs per project
snowdamiz Jun 1, 2026
104e64e
Fix terminal persistence hydration reset
snowdamiz Jun 1, 2026
3c099ac
Suppress restored terminal startup replay
snowdamiz Jun 1, 2026
2d78c15
Fix terminal tab click target
snowdamiz Jun 1, 2026
a5f8168
Enforce stale-file guards for agent edits
snowdamiz Jun 1, 2026
74cf68d
feat: add terminal autosuggestions
snowdamiz Jun 1, 2026
b358637
fix: make terminal suggestions inline only
snowdamiz Jun 1, 2026
2840631
fix: trim unsent terminal input on restore
snowdamiz Jun 1, 2026
8099de1
fix: drop trailing terminal restore control effects
snowdamiz Jun 1, 2026
9136536
fix: scrub unsaved terminal prompt input
snowdamiz Jun 1, 2026
45b0fe9
fix: clarify terminal suggestion settings
snowdamiz Jun 1, 2026
e84ba98
feat: add terminal suggestion settings
snowdamiz Jun 1, 2026
920e843
fix: restore model picker wheel scrolling
snowdamiz Jun 1, 2026
778bbe9
fix: prevent model thinking label truncation
snowdamiz Jun 1, 2026
e27fa55
pty fixes
snowdamiz Jun 1, 2026
5eb959e
doc
snowdamiz Jun 1, 2026
f1ed2e8
s workebench tests
snowdamiz Jun 1, 2026
03b2912
sav
snowdamiz Jun 1, 2026
60fd55d
improve mailbox
snowdamiz Jun 1, 2026
3f7e4d1
improve handoff routing
snowdamiz Jun 1, 2026
674d4e2
improve token calc
snowdamiz Jun 1, 2026
c95c97c
add solana rpc user configs
snowdamiz Jun 2, 2026
ca8e6ed
sensitive data input
snowdamiz Jun 2, 2026
0bbb630
refactor
snowdamiz Jun 2, 2026
31c911d
more sw tests
snowdamiz Jun 2, 2026
38dffcf
computer use manual control STRIDE
snowdamiz Jun 2, 2026
c85d94f
workflow agent improvemnets
snowdamiz Jun 2, 2026
57ae2e3
increase tool test coverage
snowdamiz Jun 2, 2026
796fb67
improve browser automation
snowdamiz Jun 2, 2026
0b6566e
debug tool fails in dev
snowdamiz Jun 2, 2026
674e024
agent timeout
snowdamiz Jun 2, 2026
cab0c52
memory reinforcement
snowdamiz Jun 2, 2026
9d08cc9
fix agent route suggestions
snowdamiz Jun 2, 2026
e72cdc1
save
snowdamiz Jun 3, 2026
7eef1e1
save
snowdamiz Jun 3, 2026
67fec57
save
snowdamiz Jun 3, 2026
e081e63
feat: add source-control settings and tool-using commit message gener…
snowdamiz Jun 3, 2026
1b48a36
refactor: improve vcs sidebar width motion, diff pane and banner anim…
snowdamiz Jun 3, 2026
d4d14d5
save
snowdamiz Jun 4, 2026
5ac19cc
save
snowdamiz Jun 4, 2026
83401cc
refactor: improve attachment compatibility and browser dev server han…
snowdamiz Jun 4, 2026
24c24d4
feat: add session notifications sidebar
snowdamiz Jun 4, 2026
98e458a
refactor(xero): share sidebar header, improve global unread counts
snowdamiz Jun 4, 2026
2628fc9
feat: show animated border on project rail for active agent runs
snowdamiz Jun 4, 2026
22cba2c
Add completed session count badges to project rail
snowdamiz Jun 4, 2026
abee8b1
feat: hold previous runtime and animate surfaces on agent session switch
snowdamiz Jun 4, 2026
5956e3c
refactor: replace memory review queue with enabled/disabled model
snowdamiz Jun 5, 2026
8e5b07a
Replace native title attributes with accessible tooltips across shell UI
snowdamiz Jun 5, 2026
92d93c4
feat: animate new panes on enter and reduce layout thrash
snowdamiz Jun 5, 2026
e732db5
refactor(browser tool): persist and drag floating toolbar across modes
snowdamiz Jun 5, 2026
c3f8c98
feat: add owned-agent action rejection and improve routing/continuity…
snowdamiz Jun 5, 2026
336cc65
feat: scope browser tabs and sidebar state to the active project
snowdamiz Jun 5, 2026
42ff9bf
feat: enable OpenAI GPT attachment support and improve edit recovery
snowdamiz Jun 5, 2026
07f3321
fix: add durable action ids and scoped approval routing for owned-age…
snowdamiz Jun 5, 2026
4c40e4a
refactor: simplify commit message generation to single bounded diff turn
snowdamiz Jun 5, 2026
fd0aabf
feat: attach browser sketch images and dev server targets to agent pr…
snowdamiz Jun 5, 2026
781c5f1
feat: add drag-and-drop tab reordering and tighten runtime prompt cre…
snowdamiz Jun 6, 2026
87283c5
save
snowdamiz Jun 11, 2026
2a2b199
save
snowdamiz Jun 11, 2026
93c9f03
save
snowdamiz Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
292 changes: 292 additions & 0 deletions AGENT-RUN-ACTION-REQUEST-FIX-PLAN.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Build prerequisite: `protoc` must be on PATH (the LanceDB-backed agent memory store pulls lance-* crates whose build scripts compile vendored .proto files). On macOS: `brew install protobuf`.
- Run scooped tests and format instead of repo wide when working with rust to save time and storage.
- Dont create branches or stash unless user asks, there may be multiple agents working at the same time and doing this will break things
- When running in development, you should only be using the data in Support/dev.sn0w.xero

## Stages vs. Workflow (terminology)

Expand Down
364 changes: 0 additions & 364 deletions COMPUTER-USE-SYSTEM-CONTROL-AUDIT-PLAN.md

This file was deleted.

13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ Detected/used CLIs include:

If tools are missing, workbench surfaces degraded/missing-toolchain states rather than crashing.

For the current Solana workbench and autonomous tool coverage map, see
`docs/solana-workbench-tool-coverage-audit.md`.

### 4) Server features

- Postgres is provided by `server/docker-compose.yml` in local development.
Expand Down Expand Up @@ -379,6 +382,10 @@ Use `--json` on batch commands for scriptable output, and `--app-data-dir PATH`

The agent TUI parity matrix lives in `docs/agent-tui-parity.md`. Desktop-only browser viewport, emulator live panes, graphical canvas gestures, window chrome, and microphone dictation remain explicit exclusions; renderer-independent workflows are exposed through terminal-native panes or CLI commands.

Owned-agent file mutations use stale-file protection: agents must observe existing files and pass current SHA-256 guards before writing, while command mutations invalidate prior observations. See `docs/agent-stale-file-protection.md` for the mutation-path inventory and retry contract.

Context pressure, compaction, and same-type handoff behavior are audited in `docs/context-exhaustion-compaction-handoff.md`, including the proposed continuity model-routing rollout.

Scoped verification for harness work:

```bash
Expand Down Expand Up @@ -453,15 +460,13 @@ XERO_SKIP_DICTATION_SHIM=1
These are optional and only needed for specific runtime integrations:

```bash
# Custom web-search provider used by autonomous web tools
XERO_AUTONOMOUS_WEB_SEARCH_URL=https://...
XERO_AUTONOMOUS_WEB_SEARCH_BEARER_TOKEN=...

# Solana workbench resource overrides
XERO_SOLANA_RESOURCE_ROOT=/path/to/resources
XERO_SOLANA_TOOLCHAIN_ROOT=/path/to/toolchain
```

Autonomous web search is configured in the desktop app under Settings -> Web Search. Xero stores non-secret provider settings in OS app-data and stores API keys through the same provider credential table used for LLM providers. The custom endpoint contract is `GET <endpoint>?q=<query>&limit=<count>` with a JSON response shaped as `{ "results": [{ "title": string, "url": string, "snippet"?: string }] }`.

---

## Persistence Model
Expand Down
66 changes: 66 additions & 0 deletions client/components/xero/agent-dock-sidebar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ import { createXeroHighChurnStore } from '@/src/features/xero/use-xero-desktop-s
import type { AgentSessionView } from '@/src/lib/xero-model'

interface CapturedRuntimeProps {
active?: boolean
density?: 'comfortable' | 'compact'
inSidebar?: boolean
sidebarSessions?: readonly AgentSessionView[]
onCloseSidebar?: () => void
onSelectSidebarSession?: (id: string) => void
onClearSidebarChat?: () => void
sidebarChatClearDisabled?: boolean
sidebarChatClearPending?: boolean
sidebarChatClearTitle?: string
onCreateSession?: () => void
isCreatingSession?: boolean
agentCreateCanvasIncluded?: boolean
Expand All @@ -21,11 +26,16 @@ interface CapturedRuntimeProps {
vi.mock('@/components/xero/agent-runtime/live-agent-runtime', () => ({
LiveAgentRuntimeView: ({
agent,
active,
density,
inSidebar,
sidebarSessions,
onCloseSidebar,
onSelectSidebarSession,
onClearSidebarChat,
sidebarChatClearDisabled,
sidebarChatClearPending,
sidebarChatClearTitle,
onCreateSession,
isCreatingSession,
agentCreateCanvasIncluded,
Expand All @@ -34,6 +44,7 @@ vi.mock('@/components/xero/agent-runtime/live-agent-runtime', () => ({
if (!agent) return null
return (
<div data-testid="live-agent-runtime">
<div data-testid="live-agent-runtime-active">{active ? 'true' : 'false'}</div>
<div data-testid="live-agent-runtime-density">{density}</div>
<div data-testid="live-agent-runtime-in-sidebar">{inSidebar ? 'true' : 'false'}</div>
<div data-testid="live-agent-runtime-session-count">{sidebarSessions?.length ?? 0}</div>
Expand All @@ -46,6 +57,14 @@ vi.mock('@/components/xero/agent-runtime/live-agent-runtime', () => ({
<button type="button" onClick={() => onCloseSidebar?.()}>
mock-close
</button>
<button
type="button"
disabled={sidebarChatClearDisabled || sidebarChatClearPending}
title={sidebarChatClearTitle}
onClick={() => onClearSidebarChat?.()}
>
mock-clear-chat
</button>
<button
type="button"
disabled={isCreatingSession}
Expand Down Expand Up @@ -121,6 +140,15 @@ const dummyAgent = {
},
} as unknown as ComponentProps<typeof AgentDockSidebar>['agent']

function setViewportWidth(width: number) {
Object.defineProperty(window, 'innerWidth', {
configurable: true,
writable: true,
value: width,
})
window.dispatchEvent(new Event('resize'))
}

function renderDock(
overrides: Partial<ComponentProps<typeof AgentDockSidebar>> = {},
) {
Expand All @@ -142,16 +170,26 @@ function renderDock(

describe('AgentDockSidebar', () => {
afterEach(() => {
setViewportWidth(1024)
window.localStorage.clear()
})

it('renders the live agent runtime in sidebar mode when open with an agent', () => {
renderDock()
expect(screen.getByTestId('live-agent-runtime')).toBeInTheDocument()
expect(screen.getByTestId('live-agent-runtime-active')).toHaveTextContent('true')
expect(screen.getByTestId('live-agent-runtime-in-sidebar')).toHaveTextContent('true')
expect(screen.getByTestId('live-agent-runtime-session-count')).toHaveTextContent('2')
})

it('prerenders the agent runtime while closed during surface prewarm', () => {
renderDock({ open: false, prewarm: true })

expect(screen.getByTestId('live-agent-runtime')).toBeInTheDocument()
expect(screen.getByTestId('live-agent-runtime-active')).toHaveTextContent('false')
expect(screen.queryByText('No active session')).not.toBeInTheDocument()
})

it('keeps the runtime comfortable until the sidebar is below the compact breakpoint', () => {
window.localStorage.setItem('xero.agentDock.width', '420')

Expand All @@ -168,6 +206,20 @@ describe('AgentDockSidebar', () => {
expect(screen.getByTestId('live-agent-runtime-density')).toHaveTextContent('compact')
})

it('uses a fixed full-width sheet on mobile viewports', () => {
setViewportWidth(390)

renderDock()

const aside = screen.getByLabelText('Agent dock')
expect(aside).toHaveClass('fixed')
expect(aside).toHaveClass('right-0')
expect(aside).toHaveClass('max-w-[100dvw]')
expect(aside).toHaveStyle({ maxWidth: '100dvw' })
expect(screen.getByRole('separator', { name: 'Resize agent dock', hidden: true })).toHaveClass('hidden')
expect(screen.getByTestId('live-agent-runtime-density')).toHaveTextContent('compact')
})

it('shows the empty state when no agent is available', () => {
renderDock({ agent: null })
expect(screen.queryByTestId('live-agent-runtime')).not.toBeInTheDocument()
Expand All @@ -184,6 +236,20 @@ describe('AgentDockSidebar', () => {
expect(onCreateSession).toHaveBeenCalledTimes(1)
})

it('forwards the Computer Use clear chat action into the agent runtime header', () => {
const onClearSidebarChat = vi.fn()
renderDock({
onClearSidebarChat,
sidebarChatClearTitle: 'Clear this sidebar chat',
})

const clearButton = screen.getByRole('button', { name: 'mock-clear-chat' })
expect(clearButton).toHaveAttribute('title', 'Clear this sidebar chat')
fireEvent.click(clearButton)

expect(onClearSidebarChat).toHaveBeenCalledTimes(1)
})

it('forwards the Agent Create canvas context into the agent runtime', () => {
renderDock({ agentCreateCanvasIncluded: true })

Expand Down
59 changes: 50 additions & 9 deletions client/components/xero/agent-dock-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client"

import { useCallback, useMemo, useRef, useState } from "react"
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { Bot, Plus } from "lucide-react"

import { cn } from "@/lib/utils"
Expand All @@ -24,8 +24,28 @@ import type {
const MIN_WIDTH = 320
const MAX_WIDTH = 720
const DEFAULT_WIDTH = 560
const MOBILE_OVERLAY_BREAKPOINT = 768
const WIDTH_STORAGE_KEY = "xero.agentDock.width"

function readViewportWidth(): number | null {
if (typeof window === "undefined") return null
return window.innerWidth
}

function useViewportWidth(): number | null {
const [viewportWidth, setViewportWidth] = useState<number | null>(() => readViewportWidth())

useEffect(() => {
if (typeof window === "undefined") return
const updateViewportWidth = () => setViewportWidth(window.innerWidth)
updateViewportWidth()
window.addEventListener("resize", updateViewportWidth)
return () => window.removeEventListener("resize", updateViewportWidth)
}, [])

return viewportWidth
}

function readPersistedWidth(): number | null {
if (typeof window === "undefined") return null
try {
Expand All @@ -50,6 +70,7 @@ function writePersistedWidth(width: number): void {

export interface AgentDockSidebarProps {
open: boolean
prewarm?: boolean
agent: AgentPaneView | null
highChurnStore: XeroHighChurnStore
sessions: readonly AgentSessionView[]
Expand All @@ -62,6 +83,7 @@ export interface AgentDockSidebarProps {
accountAvatarUrl?: string | null
accountLogin?: string | null
toolCallGroupingPreference?: AgentRuntimeProps["toolCallGroupingPreference"]
agentRoutingAutoSwitchEnabled?: AgentRuntimeProps["agentRoutingAutoSwitchEnabled"]
customAgentDefinitions?: readonly AgentDefinitionSummaryDto[]
onOpenAgentManagement?: () => void
onCreateAgentByHand?: AgentRuntimeProps["onCreateAgentByHand"]
Expand All @@ -75,6 +97,11 @@ export interface AgentDockSidebarProps {
onStartRuntimeRun?: AgentRuntimeProps["onStartRuntimeRun"]
onUpdateRuntimeRunControls?: AgentRuntimeProps["onUpdateRuntimeRunControls"]
onComposerControlsChange?: AgentRuntimeProps["onComposerControlsChange"]
onClearSidebarChat?: AgentRuntimeProps["onClearSidebarChat"]
sidebarChatClearDisabled?: AgentRuntimeProps["sidebarChatClearDisabled"]
sidebarChatClearLabel?: AgentRuntimeProps["sidebarChatClearLabel"]
sidebarChatClearPending?: AgentRuntimeProps["sidebarChatClearPending"]
sidebarChatClearTitle?: AgentRuntimeProps["sidebarChatClearTitle"]
onStartRuntimeSession?: AgentRuntimeProps["onStartRuntimeSession"]
onStopRuntimeRun?: AgentRuntimeProps["onStopRuntimeRun"]
onSubmitManualCallback?: AgentRuntimeProps["onSubmitManualCallback"]
Expand All @@ -90,11 +117,11 @@ export interface AgentDockSidebarProps {
onPendingInitialRuntimeAgentIdConsumed?: AgentRuntimeProps["onPendingInitialRuntimeAgentIdConsumed"]
pendingComposerInsert?: AgentRuntimeProps["pendingComposerInsert"]
onPendingComposerInsertConsumed?: AgentRuntimeProps["onPendingComposerInsertConsumed"]
browserContextLoading?: AgentRuntimeProps["browserContextLoading"]
}

export function AgentDockSidebar({
open,
prewarm = false,
agent,
highChurnStore,
sessions,
Expand All @@ -107,8 +134,11 @@ export function AgentDockSidebar({
}: AgentDockSidebarProps) {
const [width, setWidth] = useState<number>(() => readPersistedWidth() ?? DEFAULT_WIDTH)
const [isResizing, setIsResizing] = useState(false)
const viewportWidth = useViewportWidth()
const isMobileOverlay = viewportWidth !== null && viewportWidth < MOBILE_OVERLAY_BREAKPOINT
const renderedWidth = isMobileOverlay && viewportWidth !== null ? viewportWidth : width
const motionOpen = useSidebarOpenMotion(open)
const targetWidth = motionOpen ? width : 0
const targetWidth = motionOpen ? renderedWidth : 0
const widthMotion = useSidebarWidthMotion(targetWidth, { isResizing })
const widthRef = useRef(width)
widthRef.current = width
Expand All @@ -117,6 +147,7 @@ export function AgentDockSidebar({
() => sessions.filter((session) => session.isActive),
[sessions],
)
const shouldRenderRuntime = Boolean(agent && (open || prewarm))

const handleResizeStart = useCallback((event: React.PointerEvent<HTMLDivElement>) => {
if (event.button !== 0) return
Expand Down Expand Up @@ -171,11 +202,17 @@ export function AgentDockSidebar({
aria-label="Agent dock"
className={cn(
widthMotion.islandClassName,
"relative flex shrink-0 flex-col overflow-hidden bg-sidebar",
"flex shrink-0 flex-col overflow-hidden bg-sidebar",
isMobileOverlay
? "fixed inset-y-0 right-0 z-50 max-w-[100dvw] shadow-2xl"
: "relative",
open ? "border-l border-border/80" : "border-l-0",
)}
inert={!open ? true : undefined}
style={widthMotion.style}
style={{
...widthMotion.style,
maxWidth: isMobileOverlay ? "100dvw" : undefined,
}}
>
<div
aria-label="Resize agent dock"
Expand All @@ -187,25 +224,29 @@ export function AgentDockSidebar({
"absolute inset-y-0 -left-[3px] z-10 w-[6px] cursor-col-resize bg-transparent transition-colors",
"hover:bg-primary/30",
isResizing && "bg-primary/40",
isMobileOverlay && "hidden",
)}
onKeyDown={handleResizeKey}
onPointerDown={handleResizeStart}
role="separator"
tabIndex={open ? 0 : -1}
tabIndex={open && !isMobileOverlay ? 0 : -1}
/>

<div
className="flex h-full min-w-0 shrink-0 flex-col"
style={{ width }}
style={{
width: renderedWidth,
maxWidth: isMobileOverlay ? "100dvw" : undefined,
}}
>
<div className="flex min-h-0 flex-1 flex-col">
{open && agent ? (
{shouldRenderRuntime ? (
<LiveAgentRuntimeView
{...runtimeProps}
active={open}
agent={agent}
highChurnStore={highChurnStore}
density={width < SIDEBAR_AGENT_PANE_COMPACT_WIDTH_PX ? "compact" : "comfortable"}
density={renderedWidth < SIDEBAR_AGENT_PANE_COMPACT_WIDTH_PX ? "compact" : "comfortable"}
onCreateSession={onCreateSession}
isCreatingSession={isCreatingSession}
inSidebar
Expand Down
Loading
Loading