@athenaintel/react 0.41.0 → 0.41.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/agent-runtime/src/protocol.cjs +15 -0
- package/dist/agent-runtime/src/protocol.cjs.map +1 -1
- package/dist/agent-runtime/src/protocol.js +16 -1
- package/dist/agent-runtime/src/protocol.js.map +1 -1
- package/dist/agent-runtime/src/thread-snapshot-cache.cjs +2 -1
- package/dist/agent-runtime/src/thread-snapshot-cache.cjs.map +1 -1
- package/dist/agent-runtime/src/thread-snapshot-cache.js +2 -1
- package/dist/agent-runtime/src/thread-snapshot-cache.js.map +1 -1
- package/dist/chat-ui/lib/asset-urls.cjs +6 -1
- package/dist/chat-ui/lib/asset-urls.cjs.map +1 -1
- package/dist/chat-ui/lib/asset-urls.d.ts +6 -1
- package/dist/chat-ui/lib/asset-urls.js +7 -2
- package/dist/chat-ui/lib/asset-urls.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lib/athena-urls.cjs +17 -0
- package/dist/lib/athena-urls.cjs.map +1 -1
- package/dist/lib/athena-urls.d.ts +14 -0
- package/dist/lib/athena-urls.js +17 -0
- package/dist/lib/athena-urls.js.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +4 -14
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +5 -4
- package/dist/runtime/useAthenaStatewireRuntime.js +4 -14
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/workbench/session-workbench-model.cjs +0 -18
- package/dist/workbench/session-workbench-model.cjs.map +1 -1
- package/dist/workbench/session-workbench-model.d.ts +0 -13
- package/dist/workbench/session-workbench-model.js +0 -18
- package/dist/workbench/session-workbench-model.js.map +1 -1
- package/dist/workbench/session-workbench-panes.cjs +1 -1
- package/dist/workbench/session-workbench-panes.cjs.map +1 -1
- package/dist/workbench/session-workbench-panes.js +2 -2
- package/dist/workbench/session-workbench-panes.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-workbench-model.js","sources":["../../src/workbench/session-workbench-model.ts"],"sourcesContent":["/**\n * Pure derivations behind `SessionWorkbench`: the Shell pane's rows from the\n * transcript's `execute` calls, the Tasks pane's plan from the thread's\n * `write_todos` state, the Computer pane's choice of machine, and the tab\n * strip's per-thread open/active state. React-free so the panes stay thin and\n * hosts building their own panes reuse the same rules.\n */\nimport {\n EXECUTE_TOOL_NAME,\n parseExecuteOutput,\n readTruncatedToolOutputArtifact,\n summarizeShellCommand,\n} from '@athenaintel/agent-runtime';\nimport { readMessageCreatedAt } from '../chat/message-time';\nimport { deriveAthenaAppUrl } from '../lib/athena-urls';\nimport { isRecord } from '../lib/utils';\nimport { type PlanStep, parseTodoPlan } from '../tools/write-todos-tool-ui';\nimport type { SessionWorkspace, SessionWorkspaceAsset } from './session-workspace-api';\n\n// ─── Transcript shape ────────────────────────────────────────────────\n\n/**\n * The slice of an assistant-ui thread message the workbench reads — a\n * structural subset of `ThreadMessage`, so tests and hosts can hand plain\n * objects.\n */\nexport interface WorkbenchMessage {\n readonly id: string;\n readonly role: string;\n readonly content: readonly unknown[];\n readonly metadata?: { readonly custom?: Record<string, unknown> } | undefined;\n}\n\ninterface ToolCallPart {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n argsText: string | undefined;\n result: unknown;\n isError: boolean;\n artifact: unknown;\n}\n\nfunction readToolCallPart(part: unknown): ToolCallPart | null {\n if (!isRecord(part) || part.type !== 'tool-call') return null;\n const { toolCallId, toolName, args, argsText, result, isError, artifact } = part;\n if (typeof toolName !== 'string' || typeof toolCallId !== 'string') return null;\n return {\n toolCallId,\n toolName,\n args: isRecord(args) ? args : {},\n argsText: typeof argsText === 'string' ? argsText : undefined,\n result,\n isError: isError === true,\n artifact,\n };\n}\n\n/** A tool result as text: a string as is, text parts joined, `{content}` unwrapped. */\nexport function toolResultText(result: unknown): string | null {\n if (result === undefined || result === null) return null;\n if (typeof result === 'string') return result;\n if (Array.isArray(result)) {\n const texts = result.flatMap((part) =>\n isRecord(part) && part.type === 'text' && typeof part.text === 'string' ? [part.text] : [],\n );\n return texts.length > 0 ? texts.join('\\n') : JSON.stringify(result);\n }\n if (isRecord(result) && typeof result.content === 'string') return result.content;\n return JSON.stringify(result);\n}\n\n// ─── Shell ───────────────────────────────────────────────────────────\n\n/** How a shell command ended, as far as the transcript says. */\nexport type ShellRowStatus = 'running' | 'succeeded' | 'failed' | 'unknown';\n\n/** Where a command ran: a computer (by asset id) or the session's own sandbox. */\nexport interface ShellMachine {\n /** `null` for the session sandbox (an `execute` without `sandbox_asset_id`). */\n assetId: string | null;\n label: string;\n}\n\nexport interface ShellRow {\n /** The tool call id — stable across renders. */\n id: string;\n command: string;\n /** The command's first non-blank line. */\n firstLine: string;\n /** Lines after the first. */\n extraLines: number;\n machine: ShellMachine;\n status: ShellRowStatus;\n exitCode: number | null;\n /** The output without its status notes, clipped to {@link SHELL_OUTPUT_PREVIEW_CHARS}. */\n output: string;\n /** The output shown is not all of it (clipped here, cut by the backend, or not loaded). */\n outputPartial: boolean;\n /** ISO time of the turn that ran it, when the runtime stamped one. */\n createdAt: string | null;\n}\n\n/** Characters of output a row keeps for its expanded view. */\nexport const SHELL_OUTPUT_PREVIEW_CHARS = 4000;\n\n/** The label for the session's own sandbox. */\nexport const SESSION_SANDBOX_LABEL = 'Session sandbox';\n\n/**\n * Name a machine: a computer the workspace lists by its title, a bare\n * `sandbox_asset_id` the caller cannot see by its id, the session sandbox by\n * {@link SESSION_SANDBOX_LABEL} (or by the session computer, when the session\n * is bound to one).\n */\nexport function shellMachine({\n sandboxAssetId,\n workspace,\n}: {\n sandboxAssetId: string | null;\n workspace: SessionWorkspace | null | undefined;\n}): ShellMachine {\n const targetId = sandboxAssetId ?? workspace?.sessionComputerAssetId ?? null;\n if (targetId === null) return { assetId: null, label: SESSION_SANDBOX_LABEL };\n const computer = workspace?.computers.find((entry) => entry.assetId === targetId);\n return { assetId: targetId, label: computer?.title ?? targetId };\n}\n\nfunction shellStatus({\n result,\n exitCode,\n isError,\n}: {\n result: unknown;\n exitCode: number | null;\n isError: boolean;\n}): ShellRowStatus {\n if (result === undefined) return 'running';\n if (exitCode !== null) return exitCode === 0 ? 'succeeded' : 'failed';\n return isError ? 'failed' : 'unknown';\n}\n\n/**\n * Every `execute` call in the transcript, newest first. Commands still\n * running read `running`; one whose output the live window cut reads its exit\n * note only when the loaded text still carries it (`unknown` otherwise).\n */\nexport function deriveShellRows({\n messages,\n workspace,\n}: {\n messages: readonly WorkbenchMessage[];\n workspace?: SessionWorkspace | null;\n}): ShellRow[] {\n const rows: ShellRow[] = [];\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n const createdAt = readMessageCreatedAt(message.metadata?.custom);\n for (const raw of message.content) {\n const part = readToolCallPart(raw);\n if (!part || part.toolName !== EXECUTE_TOOL_NAME) continue;\n const command = typeof part.args.command === 'string' ? part.args.command : '';\n const sandboxAssetId =\n typeof part.args.sandbox_asset_id === 'string' && part.args.sandbox_asset_id\n ? part.args.sandbox_asset_id\n : null;\n const text = toolResultText(part.result);\n const parsed = text === null ? null : parseExecuteOutput(text);\n const body = parsed?.body ?? '';\n const clipped = body.length > SHELL_OUTPUT_PREVIEW_CHARS;\n const { firstLine, extraLines } = summarizeShellCommand(command);\n rows.push({\n id: part.toolCallId,\n command,\n firstLine,\n extraLines,\n machine: shellMachine({ sandboxAssetId, workspace }),\n status: shellStatus({\n result: part.result,\n exitCode: parsed?.exitCode ?? null,\n isError: part.isError,\n }),\n exitCode: parsed?.exitCode ?? null,\n output: clipped ? body.slice(0, SHELL_OUTPUT_PREVIEW_CHARS) : body,\n outputPartial:\n clipped ||\n parsed?.truncated === true ||\n readTruncatedToolOutputArtifact(part.artifact) !== null,\n createdAt,\n });\n }\n }\n return rows.reverse();\n}\n\n/** Rows whose command, machine or output contains every word of `query` (case-insensitive). */\nexport function filterShellRows(rows: readonly ShellRow[], query: string): ShellRow[] {\n const words = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return [...rows];\n return rows.filter((row) => {\n const haystack = `${row.command}\\n${row.machine.label}\\n${row.output}`.toLowerCase();\n return words.every((word) => haystack.includes(word));\n });\n}\n\n// ─── Tasks ───────────────────────────────────────────────────────────\n\nexport interface TaskProgress {\n steps: PlanStep[];\n /** Steps completed. */\n done: number;\n total: number;\n}\n\n/** The plan with its \"N/M done\" counts. */\nexport function taskProgress(steps: readonly PlanStep[]): TaskProgress {\n return {\n steps: [...steps],\n done: steps.filter((step) => step.status === 'completed').length,\n total: steps.length,\n };\n}\n\n/**\n * The session's current plan: the thread state's `todos` channel (the\n * deepagents plan the backend keeps — authoritative whenever it is an array,\n * an empty one included: a cleared plan stays cleared), else the newest\n * `write_todos` call in the loaded transcript, else empty. The transcript\n * fallback covers a host whose wire does not carry the channel.\n */\nexport function deriveTaskSteps({\n stateTodos,\n messages,\n}: {\n stateTodos: unknown;\n messages: readonly WorkbenchMessage[];\n}): PlanStep[] {\n if (Array.isArray(stateTodos)) {\n return parseTodoPlan({ args: { todos: stateTodos } }).steps;\n }\n for (let m = messages.length - 1; m >= 0; m -= 1) {\n const message = messages[m];\n if (!message || message.role !== 'assistant') continue;\n for (let p = message.content.length - 1; p >= 0; p -= 1) {\n const part = readToolCallPart(message.content[p]);\n if (!part || part.toolName !== 'write_todos') continue;\n const steps = parseTodoPlan({\n args: part.args,\n argsText: part.argsText,\n result: part.result,\n }).steps;\n if (steps.length > 0) return steps;\n }\n }\n return [];\n}\n\n// ─── Computers ───────────────────────────────────────────────────────\n\n/**\n * The computer the Computer pane leads with: the session's bound computer,\n * else the computer the session touched most recently. The rest follow.\n */\nexport function workspaceComputers(workspace: SessionWorkspace | null | undefined): {\n primary: SessionWorkspaceAsset | null;\n others: SessionWorkspaceAsset[];\n} {\n const computers = workspace?.computers ?? [];\n const primary =\n computers.find((computer) => computer.role === 'session_computer') ?? computers[0] ?? null;\n return {\n primary,\n others: computers.filter((computer) => computer !== primary),\n };\n}\n\nexport type ComputerStateTone = 'running' | 'transition' | 'stopped' | 'error';\n\nconst COMPUTER_STATE_BADGES: Record<string, { label: string; tone: ComputerStateTone }> = {\n started: { label: 'Running', tone: 'running' },\n running: { label: 'Running', tone: 'running' },\n ready: { label: 'Running', tone: 'running' },\n starting: { label: 'Starting', tone: 'transition' },\n pending: { label: 'Starting', tone: 'transition' },\n restoring: { label: 'Restoring', tone: 'transition' },\n resuming: { label: 'Waking', tone: 'transition' },\n stopping: { label: 'Stopping', tone: 'transition' },\n pausing: { label: 'Pausing', tone: 'transition' },\n stopped: { label: 'Stopped', tone: 'stopped' },\n paused: { label: 'Paused', tone: 'stopped' },\n suspended: { label: 'Sleeping', tone: 'stopped' },\n archived: { label: 'Archived', tone: 'stopped' },\n error: { label: 'Error', tone: 'error' },\n failed: { label: 'Error', tone: 'error' },\n errored: { label: 'Error', tone: 'error' },\n};\n\n/**\n * The badge for a computer's runtime state, or `null` when the state says\n * nothing a person can act on (`unknown`). A stop someone asked for wins over\n * a runtime that has not caught up yet.\n */\nexport function computerStateBadge(status: {\n state: string;\n explicitStop: string | null;\n}): { label: string; tone: ComputerStateTone } | null {\n if (status.explicitStop === 'stopping') return { label: 'Stopping', tone: 'transition' };\n const state = status.state.toLowerCase();\n if (state === '' || state === 'unknown') return null;\n return (\n COMPUTER_STATE_BADGES[state] ?? {\n label: state.charAt(0).toUpperCase() + state.slice(1).replace(/_/g, ' '),\n tone: 'stopped',\n }\n );\n}\n\n// ─── Assets ──────────────────────────────────────────────────────────\n\nconst ASSET_TYPE_LABELS: Record<string, string> = {\n presentation_pptx_studio: 'Presentation',\n pptx: 'PowerPoint file',\n pdf: 'PDF',\n txt: 'Text file',\n json: 'JSON',\n yaml: 'YAML',\n query_snippet: 'Query',\n web_page: 'Web page',\n browse_session: 'Browser session',\n agent_config: 'Agent',\n collab_agent: 'Agent',\n};\n\n/** A person's word for an Athena asset type (`spreadsheet` → \"Spreadsheet\"). */\nexport function assetTypeLabel(assetType: string): string {\n const known = ASSET_TYPE_LABELS[assetType];\n if (known) return known;\n if (!assetType) return 'Asset';\n const words = assetType.replace(/_/g, ' ');\n return words.charAt(0).toUpperCase() + words.slice(1);\n}\n\nconst ASSET_PANEL_TYPES: Record<string, 'presentation' | 'spreadsheet' | 'document' | 'notebook'> = {\n presentation: 'presentation',\n presentation_pptx_studio: 'presentation',\n spreadsheet: 'spreadsheet',\n document: 'document',\n notebook: 'notebook',\n};\n\n/** The asset panel's viewer for an asset type, or `null` when the panel has none. */\nexport function assetPanelTypeOf(\n assetType: string,\n): 'presentation' | 'spreadsheet' | 'document' | 'notebook' | null {\n return ASSET_PANEL_TYPES[assetType] ?? null;\n}\n\nfunction originOf(url: string): string | null {\n try {\n return new URL(url).origin;\n } catch {\n return null;\n }\n}\n\n/**\n * The Athena frontend an \"Open in Athena\" link points at. The provider's\n * `appUrl` is that frontend, except in an app a computer serves: Marathon's\n * `/_athena/auth` mints `appUrl` as the app's OWN origin, so a link built on\n * it opens the app instead of Athena. When `appUrl` is the page's own origin\n * and the Agora base belongs to a known Athena deployment, the deployment's\n * frontend wins (on Olympus itself the two are the same origin anyway).\n */\nexport function athenaLinkAppUrl({\n appUrl,\n backendUrl,\n pageOrigin,\n}: {\n appUrl: string;\n backendUrl: string;\n pageOrigin: string | null;\n}): string {\n const deployed = deriveAthenaAppUrl({ backendUrl });\n if (deployed && pageOrigin !== null && originOf(appUrl) === pageOrigin) return deployed;\n return appUrl;\n}\n\n// ─── Pull requests ───────────────────────────────────────────────────\n\nconst REVIEW_DECISION_LABELS: Record<string, string> = {\n APPROVED: 'approved',\n CHANGES_REQUESTED: 'changes requested',\n REVIEW_REQUIRED: 'review required',\n};\n\n/** GitHub's review decision in words, or `''` when there is none. */\nexport function reviewDecisionLabel(reviewDecision: string | null): string {\n if (!reviewDecision) return '';\n return REVIEW_DECISION_LABELS[reviewDecision] ?? reviewDecision.toLowerCase().replace(/_/g, ' ');\n}\n\n// ─── Tabs ────────────────────────────────────────────────────────────\n\n/** One thread's open tabs (in strip order) and its active tab. */\nexport interface WorkbenchThreadTabs {\n open: string[];\n active: string | null;\n}\n\n/** Every thread's tabs this workbench has seen, in memory only. */\nexport type WorkbenchTabsState = Readonly<Record<string, WorkbenchThreadTabs>>;\n\nexport type WorkbenchTabsAction =\n | { type: 'open'; threadKey: string; paneId: string; defaults: WorkbenchThreadTabs }\n | { type: 'close'; threadKey: string; paneId: string; defaults: WorkbenchThreadTabs }\n | { type: 'activate'; threadKey: string; paneId: string; defaults: WorkbenchThreadTabs };\n\n/** A thread's tabs, or the defaults for a thread the workbench has not changed yet. */\nexport function threadTabs(\n state: WorkbenchTabsState,\n threadKey: string,\n defaults: WorkbenchThreadTabs,\n): WorkbenchThreadTabs {\n return state[threadKey] ?? defaults;\n}\n\n/**\n * The tab strip's transitions. Opening a tab that is already open activates\n * it; closing the active tab activates its right neighbour (else its left);\n * the first change to a thread starts from the defaults.\n */\nexport function workbenchTabsReducer(\n state: WorkbenchTabsState,\n action: WorkbenchTabsAction,\n): WorkbenchTabsState {\n const current = threadTabs(state, action.threadKey, action.defaults);\n let next: WorkbenchThreadTabs;\n switch (action.type) {\n case 'open':\n next = {\n open: current.open.includes(action.paneId)\n ? current.open\n : [...current.open, action.paneId],\n active: action.paneId,\n };\n break;\n case 'activate':\n if (!current.open.includes(action.paneId) || current.active === action.paneId) return state;\n next = { open: current.open, active: action.paneId };\n break;\n case 'close': {\n const index = current.open.indexOf(action.paneId);\n if (index < 0) return state;\n const open = current.open.filter((id) => id !== action.paneId);\n next = {\n open,\n active:\n current.active === action.paneId\n ? (open[index] ?? open[index - 1] ?? null)\n : current.active,\n };\n break;\n }\n }\n return { ...state, [action.threadKey]: next };\n}\n\n/**\n * The tabs as the strip renders them: only panes the registry still has, and\n * an active tab that is one of them (the first, when the stored one is gone).\n */\nexport function visibleThreadTabs(\n tabs: WorkbenchThreadTabs,\n paneIds: ReadonlySet<string>,\n): WorkbenchThreadTabs {\n const open = tabs.open.filter((id) => paneIds.has(id));\n const active =\n tabs.active !== null && open.includes(tabs.active) ? tabs.active : (open[0] ?? null);\n return { open, active };\n}\n\n/** The \"+\" menu's search: panes whose title or description holds the query, any case. */\nexport function filterWorkbenchPanes<P extends { title: string; description?: string }>(\n panes: readonly P[],\n query: string,\n): readonly P[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return panes;\n return panes.filter(\n (pane) =>\n pane.title.toLowerCase().includes(needle) ||\n (pane.description?.toLowerCase().includes(needle) ?? false),\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session-workbench-model.js","sources":["../../src/workbench/session-workbench-model.ts"],"sourcesContent":["/**\n * Pure derivations behind `SessionWorkbench`: the Shell pane's rows from the\n * transcript's `execute` calls, the Tasks pane's plan from the thread's\n * `write_todos` state, the Computer pane's choice of machine, and the tab\n * strip's per-thread open/active state. React-free so the panes stay thin and\n * hosts building their own panes reuse the same rules.\n */\nimport {\n EXECUTE_TOOL_NAME,\n parseExecuteOutput,\n readTruncatedToolOutputArtifact,\n summarizeShellCommand,\n} from '@athenaintel/agent-runtime';\nimport { readMessageCreatedAt } from '../chat/message-time';\nimport { isRecord } from '../lib/utils';\nimport { type PlanStep, parseTodoPlan } from '../tools/write-todos-tool-ui';\nimport type { SessionWorkspace, SessionWorkspaceAsset } from './session-workspace-api';\n\n// ─── Transcript shape ────────────────────────────────────────────────\n\n/**\n * The slice of an assistant-ui thread message the workbench reads — a\n * structural subset of `ThreadMessage`, so tests and hosts can hand plain\n * objects.\n */\nexport interface WorkbenchMessage {\n readonly id: string;\n readonly role: string;\n readonly content: readonly unknown[];\n readonly metadata?: { readonly custom?: Record<string, unknown> } | undefined;\n}\n\ninterface ToolCallPart {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n argsText: string | undefined;\n result: unknown;\n isError: boolean;\n artifact: unknown;\n}\n\nfunction readToolCallPart(part: unknown): ToolCallPart | null {\n if (!isRecord(part) || part.type !== 'tool-call') return null;\n const { toolCallId, toolName, args, argsText, result, isError, artifact } = part;\n if (typeof toolName !== 'string' || typeof toolCallId !== 'string') return null;\n return {\n toolCallId,\n toolName,\n args: isRecord(args) ? args : {},\n argsText: typeof argsText === 'string' ? argsText : undefined,\n result,\n isError: isError === true,\n artifact,\n };\n}\n\n/** A tool result as text: a string as is, text parts joined, `{content}` unwrapped. */\nexport function toolResultText(result: unknown): string | null {\n if (result === undefined || result === null) return null;\n if (typeof result === 'string') return result;\n if (Array.isArray(result)) {\n const texts = result.flatMap((part) =>\n isRecord(part) && part.type === 'text' && typeof part.text === 'string' ? [part.text] : [],\n );\n return texts.length > 0 ? texts.join('\\n') : JSON.stringify(result);\n }\n if (isRecord(result) && typeof result.content === 'string') return result.content;\n return JSON.stringify(result);\n}\n\n// ─── Shell ───────────────────────────────────────────────────────────\n\n/** How a shell command ended, as far as the transcript says. */\nexport type ShellRowStatus = 'running' | 'succeeded' | 'failed' | 'unknown';\n\n/** Where a command ran: a computer (by asset id) or the session's own sandbox. */\nexport interface ShellMachine {\n /** `null` for the session sandbox (an `execute` without `sandbox_asset_id`). */\n assetId: string | null;\n label: string;\n}\n\nexport interface ShellRow {\n /** The tool call id — stable across renders. */\n id: string;\n command: string;\n /** The command's first non-blank line. */\n firstLine: string;\n /** Lines after the first. */\n extraLines: number;\n machine: ShellMachine;\n status: ShellRowStatus;\n exitCode: number | null;\n /** The output without its status notes, clipped to {@link SHELL_OUTPUT_PREVIEW_CHARS}. */\n output: string;\n /** The output shown is not all of it (clipped here, cut by the backend, or not loaded). */\n outputPartial: boolean;\n /** ISO time of the turn that ran it, when the runtime stamped one. */\n createdAt: string | null;\n}\n\n/** Characters of output a row keeps for its expanded view. */\nexport const SHELL_OUTPUT_PREVIEW_CHARS = 4000;\n\n/** The label for the session's own sandbox. */\nexport const SESSION_SANDBOX_LABEL = 'Session sandbox';\n\n/**\n * Name a machine: a computer the workspace lists by its title, a bare\n * `sandbox_asset_id` the caller cannot see by its id, the session sandbox by\n * {@link SESSION_SANDBOX_LABEL} (or by the session computer, when the session\n * is bound to one).\n */\nexport function shellMachine({\n sandboxAssetId,\n workspace,\n}: {\n sandboxAssetId: string | null;\n workspace: SessionWorkspace | null | undefined;\n}): ShellMachine {\n const targetId = sandboxAssetId ?? workspace?.sessionComputerAssetId ?? null;\n if (targetId === null) return { assetId: null, label: SESSION_SANDBOX_LABEL };\n const computer = workspace?.computers.find((entry) => entry.assetId === targetId);\n return { assetId: targetId, label: computer?.title ?? targetId };\n}\n\nfunction shellStatus({\n result,\n exitCode,\n isError,\n}: {\n result: unknown;\n exitCode: number | null;\n isError: boolean;\n}): ShellRowStatus {\n if (result === undefined) return 'running';\n if (exitCode !== null) return exitCode === 0 ? 'succeeded' : 'failed';\n return isError ? 'failed' : 'unknown';\n}\n\n/**\n * Every `execute` call in the transcript, newest first. Commands still\n * running read `running`; one whose output the live window cut reads its exit\n * note only when the loaded text still carries it (`unknown` otherwise).\n */\nexport function deriveShellRows({\n messages,\n workspace,\n}: {\n messages: readonly WorkbenchMessage[];\n workspace?: SessionWorkspace | null;\n}): ShellRow[] {\n const rows: ShellRow[] = [];\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n const createdAt = readMessageCreatedAt(message.metadata?.custom);\n for (const raw of message.content) {\n const part = readToolCallPart(raw);\n if (!part || part.toolName !== EXECUTE_TOOL_NAME) continue;\n const command = typeof part.args.command === 'string' ? part.args.command : '';\n const sandboxAssetId =\n typeof part.args.sandbox_asset_id === 'string' && part.args.sandbox_asset_id\n ? part.args.sandbox_asset_id\n : null;\n const text = toolResultText(part.result);\n const parsed = text === null ? null : parseExecuteOutput(text);\n const body = parsed?.body ?? '';\n const clipped = body.length > SHELL_OUTPUT_PREVIEW_CHARS;\n const { firstLine, extraLines } = summarizeShellCommand(command);\n rows.push({\n id: part.toolCallId,\n command,\n firstLine,\n extraLines,\n machine: shellMachine({ sandboxAssetId, workspace }),\n status: shellStatus({\n result: part.result,\n exitCode: parsed?.exitCode ?? null,\n isError: part.isError,\n }),\n exitCode: parsed?.exitCode ?? null,\n output: clipped ? body.slice(0, SHELL_OUTPUT_PREVIEW_CHARS) : body,\n outputPartial:\n clipped ||\n parsed?.truncated === true ||\n readTruncatedToolOutputArtifact(part.artifact) !== null,\n createdAt,\n });\n }\n }\n return rows.reverse();\n}\n\n/** Rows whose command, machine or output contains every word of `query` (case-insensitive). */\nexport function filterShellRows(rows: readonly ShellRow[], query: string): ShellRow[] {\n const words = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return [...rows];\n return rows.filter((row) => {\n const haystack = `${row.command}\\n${row.machine.label}\\n${row.output}`.toLowerCase();\n return words.every((word) => haystack.includes(word));\n });\n}\n\n// ─── Tasks ───────────────────────────────────────────────────────────\n\nexport interface TaskProgress {\n steps: PlanStep[];\n /** Steps completed. */\n done: number;\n total: number;\n}\n\n/** The plan with its \"N/M done\" counts. */\nexport function taskProgress(steps: readonly PlanStep[]): TaskProgress {\n return {\n steps: [...steps],\n done: steps.filter((step) => step.status === 'completed').length,\n total: steps.length,\n };\n}\n\n/**\n * The session's current plan: the thread state's `todos` channel (the\n * deepagents plan the backend keeps — authoritative whenever it is an array,\n * an empty one included: a cleared plan stays cleared), else the newest\n * `write_todos` call in the loaded transcript, else empty. The transcript\n * fallback covers a host whose wire does not carry the channel.\n */\nexport function deriveTaskSteps({\n stateTodos,\n messages,\n}: {\n stateTodos: unknown;\n messages: readonly WorkbenchMessage[];\n}): PlanStep[] {\n if (Array.isArray(stateTodos)) {\n return parseTodoPlan({ args: { todos: stateTodos } }).steps;\n }\n for (let m = messages.length - 1; m >= 0; m -= 1) {\n const message = messages[m];\n if (!message || message.role !== 'assistant') continue;\n for (let p = message.content.length - 1; p >= 0; p -= 1) {\n const part = readToolCallPart(message.content[p]);\n if (!part || part.toolName !== 'write_todos') continue;\n const steps = parseTodoPlan({\n args: part.args,\n argsText: part.argsText,\n result: part.result,\n }).steps;\n if (steps.length > 0) return steps;\n }\n }\n return [];\n}\n\n// ─── Computers ───────────────────────────────────────────────────────\n\n/**\n * The computer the Computer pane leads with: the session's bound computer,\n * else the computer the session touched most recently. The rest follow.\n */\nexport function workspaceComputers(workspace: SessionWorkspace | null | undefined): {\n primary: SessionWorkspaceAsset | null;\n others: SessionWorkspaceAsset[];\n} {\n const computers = workspace?.computers ?? [];\n const primary =\n computers.find((computer) => computer.role === 'session_computer') ?? computers[0] ?? null;\n return {\n primary,\n others: computers.filter((computer) => computer !== primary),\n };\n}\n\nexport type ComputerStateTone = 'running' | 'transition' | 'stopped' | 'error';\n\nconst COMPUTER_STATE_BADGES: Record<string, { label: string; tone: ComputerStateTone }> = {\n started: { label: 'Running', tone: 'running' },\n running: { label: 'Running', tone: 'running' },\n ready: { label: 'Running', tone: 'running' },\n starting: { label: 'Starting', tone: 'transition' },\n pending: { label: 'Starting', tone: 'transition' },\n restoring: { label: 'Restoring', tone: 'transition' },\n resuming: { label: 'Waking', tone: 'transition' },\n stopping: { label: 'Stopping', tone: 'transition' },\n pausing: { label: 'Pausing', tone: 'transition' },\n stopped: { label: 'Stopped', tone: 'stopped' },\n paused: { label: 'Paused', tone: 'stopped' },\n suspended: { label: 'Sleeping', tone: 'stopped' },\n archived: { label: 'Archived', tone: 'stopped' },\n error: { label: 'Error', tone: 'error' },\n failed: { label: 'Error', tone: 'error' },\n errored: { label: 'Error', tone: 'error' },\n};\n\n/**\n * The badge for a computer's runtime state, or `null` when the state says\n * nothing a person can act on (`unknown`). A stop someone asked for wins over\n * a runtime that has not caught up yet.\n */\nexport function computerStateBadge(status: {\n state: string;\n explicitStop: string | null;\n}): { label: string; tone: ComputerStateTone } | null {\n if (status.explicitStop === 'stopping') return { label: 'Stopping', tone: 'transition' };\n const state = status.state.toLowerCase();\n if (state === '' || state === 'unknown') return null;\n return (\n COMPUTER_STATE_BADGES[state] ?? {\n label: state.charAt(0).toUpperCase() + state.slice(1).replace(/_/g, ' '),\n tone: 'stopped',\n }\n );\n}\n\n// ─── Assets ──────────────────────────────────────────────────────────\n\nconst ASSET_TYPE_LABELS: Record<string, string> = {\n presentation_pptx_studio: 'Presentation',\n pptx: 'PowerPoint file',\n pdf: 'PDF',\n txt: 'Text file',\n json: 'JSON',\n yaml: 'YAML',\n query_snippet: 'Query',\n web_page: 'Web page',\n browse_session: 'Browser session',\n agent_config: 'Agent',\n collab_agent: 'Agent',\n};\n\n/** A person's word for an Athena asset type (`spreadsheet` → \"Spreadsheet\"). */\nexport function assetTypeLabel(assetType: string): string {\n const known = ASSET_TYPE_LABELS[assetType];\n if (known) return known;\n if (!assetType) return 'Asset';\n const words = assetType.replace(/_/g, ' ');\n return words.charAt(0).toUpperCase() + words.slice(1);\n}\n\nconst ASSET_PANEL_TYPES: Record<string, 'presentation' | 'spreadsheet' | 'document' | 'notebook'> = {\n presentation: 'presentation',\n presentation_pptx_studio: 'presentation',\n spreadsheet: 'spreadsheet',\n document: 'document',\n notebook: 'notebook',\n};\n\n/** The asset panel's viewer for an asset type, or `null` when the panel has none. */\nexport function assetPanelTypeOf(\n assetType: string,\n): 'presentation' | 'spreadsheet' | 'document' | 'notebook' | null {\n return ASSET_PANEL_TYPES[assetType] ?? null;\n}\n\n\n// ─── Pull requests ───────────────────────────────────────────────────\n\nconst REVIEW_DECISION_LABELS: Record<string, string> = {\n APPROVED: 'approved',\n CHANGES_REQUESTED: 'changes requested',\n REVIEW_REQUIRED: 'review required',\n};\n\n/** GitHub's review decision in words, or `''` when there is none. */\nexport function reviewDecisionLabel(reviewDecision: string | null): string {\n if (!reviewDecision) return '';\n return REVIEW_DECISION_LABELS[reviewDecision] ?? reviewDecision.toLowerCase().replace(/_/g, ' ');\n}\n\n// ─── Tabs ────────────────────────────────────────────────────────────\n\n/** One thread's open tabs (in strip order) and its active tab. */\nexport interface WorkbenchThreadTabs {\n open: string[];\n active: string | null;\n}\n\n/** Every thread's tabs this workbench has seen, in memory only. */\nexport type WorkbenchTabsState = Readonly<Record<string, WorkbenchThreadTabs>>;\n\nexport type WorkbenchTabsAction =\n | { type: 'open'; threadKey: string; paneId: string; defaults: WorkbenchThreadTabs }\n | { type: 'close'; threadKey: string; paneId: string; defaults: WorkbenchThreadTabs }\n | { type: 'activate'; threadKey: string; paneId: string; defaults: WorkbenchThreadTabs };\n\n/** A thread's tabs, or the defaults for a thread the workbench has not changed yet. */\nexport function threadTabs(\n state: WorkbenchTabsState,\n threadKey: string,\n defaults: WorkbenchThreadTabs,\n): WorkbenchThreadTabs {\n return state[threadKey] ?? defaults;\n}\n\n/**\n * The tab strip's transitions. Opening a tab that is already open activates\n * it; closing the active tab activates its right neighbour (else its left);\n * the first change to a thread starts from the defaults.\n */\nexport function workbenchTabsReducer(\n state: WorkbenchTabsState,\n action: WorkbenchTabsAction,\n): WorkbenchTabsState {\n const current = threadTabs(state, action.threadKey, action.defaults);\n let next: WorkbenchThreadTabs;\n switch (action.type) {\n case 'open':\n next = {\n open: current.open.includes(action.paneId)\n ? current.open\n : [...current.open, action.paneId],\n active: action.paneId,\n };\n break;\n case 'activate':\n if (!current.open.includes(action.paneId) || current.active === action.paneId) return state;\n next = { open: current.open, active: action.paneId };\n break;\n case 'close': {\n const index = current.open.indexOf(action.paneId);\n if (index < 0) return state;\n const open = current.open.filter((id) => id !== action.paneId);\n next = {\n open,\n active:\n current.active === action.paneId\n ? (open[index] ?? open[index - 1] ?? null)\n : current.active,\n };\n break;\n }\n }\n return { ...state, [action.threadKey]: next };\n}\n\n/**\n * The tabs as the strip renders them: only panes the registry still has, and\n * an active tab that is one of them (the first, when the stored one is gone).\n */\nexport function visibleThreadTabs(\n tabs: WorkbenchThreadTabs,\n paneIds: ReadonlySet<string>,\n): WorkbenchThreadTabs {\n const open = tabs.open.filter((id) => paneIds.has(id));\n const active =\n tabs.active !== null && open.includes(tabs.active) ? tabs.active : (open[0] ?? null);\n return { open, active };\n}\n\n/** The \"+\" menu's search: panes whose title or description holds the query, any case. */\nexport function filterWorkbenchPanes<P extends { title: string; description?: string }>(\n panes: readonly P[],\n query: string,\n): readonly P[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return panes;\n return panes.filter(\n (pane) =>\n pane.title.toLowerCase().includes(needle) ||\n (pane.description?.toLowerCase().includes(needle) ?? false),\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -346,7 +346,7 @@ function useAssetHref(assetId) {
|
|
|
346
346
|
const pageOrigin = typeof window === "undefined" ? null : window.location.origin;
|
|
347
347
|
try {
|
|
348
348
|
return athenaUrls.createAthenaSpacesUrl({
|
|
349
|
-
appUrl:
|
|
349
|
+
appUrl: athenaUrls.athenaLinkAppUrl({ appUrl, backendUrl, pageOrigin }),
|
|
350
350
|
assetIds: assetId
|
|
351
351
|
});
|
|
352
352
|
} catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-workbench-panes.cjs","sources":["../../src/workbench/session-workbench-panes.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * The built-in panes of `SessionWorkbench` — Tasks, Shell, Computer, Pull\n * requests and Attachments. Each reads one source:\n *\n * - Tasks: the thread state's `todos` channel (the deepagents plan), else the\n * newest `write_todos` call in the loaded transcript.\n * - Shell: every `execute` call in the loaded transcript; while the thread has\n * older history the chat has not loaded, it says so and loads the next page\n * on request (`StatewireHistoryContext`).\n * - Computer / Attachments: the session's workspace\n * (`GET /api/conversations/threads/{id}/workspace`), plus the computer's\n * status and SSH target; the Computer pane also shows the computer's screen\n * live (`ComputerLiveDesktop`).\n * - Pull requests: the thread list's live pull-request state for the session.\n */\nimport { useAuiState } from '@assistant-ui/react';\nimport { useStatewireState } from '@assistant-ui/react-statewire';\nimport {\n type ConversationPullRequest,\n hasStatewireThreadExtras,\n readDeepAgentStreamValues,\n} from '@athenaintel/agent-runtime';\nimport {\n AlertCircleIcon,\n BookOpenIcon,\n CheckIcon,\n CircleDashedIcon,\n CopyIcon,\n ExternalLinkIcon,\n FileIcon,\n FileSpreadsheetIcon,\n FileTextIcon,\n FolderIcon,\n GitPullRequestIcon,\n ImageIcon,\n ListChecksIcon,\n LoaderIcon,\n MonitorIcon,\n PaperclipIcon,\n PresentationIcon,\n SearchIcon,\n TerminalIcon,\n XIcon,\n} from 'lucide-react';\nimport { type FC, type ReactNode, useMemo, useState } from 'react';\nimport { type AssetType as AssetPanelType, useAssetPanelStore } from '../assets/asset-panel-store';\nimport { createAthenaSpacesUrl } from '../lib/athena-urls';\nimport { cn } from '../lib/utils';\nimport { useAthenaConfig } from '../provider/AthenaContext';\nimport {\n type StatewireHistoryState,\n useStatewireHistory,\n} from '../provider/statewire-history-context';\nimport { PR_CHECKS_LABEL, PR_STATE_CLASS, PR_STATE_ICON } from '../threads/pull-request-display';\nimport {\n orderedPullRequests,\n pullRequestChipState,\n relativeTime,\n} from '../threads/session-list-model';\nimport { useAthenaStatewireThreadList } from '../threads/statewire-thread-list';\nimport { useAthenaSessionAttention } from '../threads/use-athena-session-attention';\nimport { PlanStepMarker, type PlanStepStatus } from '../tools/write-todos-tool-ui';\nimport {\n type SessionWorkbenchPane,\n useSessionWorkbench,\n useSessionWorkbenchWorkspace,\n} from './session-workbench-context';\nimport {\n assetPanelTypeOf,\n assetTypeLabel,\n athenaLinkAppUrl,\n computerStateBadge,\n deriveShellRows,\n deriveTaskSteps,\n filterShellRows,\n reviewDecisionLabel,\n type ShellRow,\n type ShellRowStatus,\n taskProgress,\n workspaceComputers,\n} from './session-workbench-model';\nimport { ComputerLiveDesktop } from './ComputerLiveDesktop';\nimport type { SessionWorkspaceAsset } from './session-workspace-api';\nimport { useAthenaComputerSshAccess, useAthenaComputerStatus } from './use-session-workspace';\n\n// ─── Shared pieces ───────────────────────────────────────────────────\n\nconst FOCUS_RING_CLASS =\n 'outline-none focus-visible:ring-2 focus-visible:ring-ring/60 focus-visible:ring-offset-0';\n\nconst PaneEmpty: FC<{\n icon: FC<{ className?: string }>;\n title: string;\n children?: ReactNode;\n}> = ({ icon: Icon, title, children }) => (\n <div className=\"flex h-full min-h-40 flex-col items-center justify-center gap-2 px-6 py-10 text-center\">\n <Icon className=\"size-5 text-muted-foreground/70\" />\n <p className=\"font-medium text-foreground text-sm\">{title}</p>\n {children ? <p className=\"max-w-64 text-muted-foreground text-xs leading-snug\">{children}</p> : null}\n </div>\n);\n\nconst PaneError: FC<{ error: Error }> = ({ error }) => (\n <div role=\"alert\" className=\"m-3 flex items-start gap-2 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-red-900 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0\" aria-hidden />\n <span className=\"min-w-0 flex-1 break-words\">{error.message}</span>\n </div>\n);\n\nconst PaneSkeleton: FC = () => (\n <div className=\"flex flex-col gap-2 p-3\" aria-busy=\"true\" aria-label=\"Loading\">\n {[0, 1, 2].map((row) => (\n <div key={row} className=\"h-10 animate-pulse rounded-lg bg-muted\" />\n ))}\n </div>\n);\n\nconst SectionHeading: FC<{ children: ReactNode; trailing?: ReactNode }> = ({ children, trailing }) => (\n <div className=\"flex items-center justify-between gap-2 px-3 pt-3 pb-1.5\">\n <h3 className=\"font-medium text-[11px] text-muted-foreground uppercase tracking-wide\">{children}</h3>\n {trailing}\n </div>\n);\n\n/** The `title` tooltip for an ISO time: the full local date and time. */\nfunction fullTime(iso: string | null): string | undefined {\n if (!iso) return undefined;\n const time = Date.parse(iso);\n return Number.isNaN(time) ? undefined : new Date(time).toLocaleString();\n}\n\n/** Statewire-only panes read the transcript and thread state; elsewhere they say so. */\nconst RequiresStatewireThread: FC<{ children: ReactNode; icon: FC<{ className?: string }> }> = ({\n children,\n icon,\n}) => {\n const extras = useAuiState((state) => state.thread.extras);\n if (!hasStatewireThreadExtras(extras)) {\n return <PaneEmpty icon={icon} title=\"No live session\">Open a session to see this pane.</PaneEmpty>;\n }\n return <>{children}</>;\n};\n\n// ─── Tasks ───────────────────────────────────────────────────────────\n\nconst TASK_STATUS_LABEL: Record<PlanStepStatus, string> = {\n pending: 'To do',\n in_progress: 'In progress',\n completed: 'Done',\n failed: 'Failed',\n cancelled: 'Cancelled',\n};\n\nconst TasksPaneContent: FC = () => {\n const stateTodos = useStatewireState((state) => readDeepAgentStreamValues(state).todos);\n const messages = useAuiState((state) => state.thread.messages);\n const progress = useMemo(\n () => taskProgress(deriveTaskSteps({ stateTodos, messages })),\n [stateTodos, messages],\n );\n if (progress.total === 0) {\n return (\n <PaneEmpty icon={ListChecksIcon} title=\"No plan yet\">\n When the agent writes a plan, its steps show here as it works through them.\n </PaneEmpty>\n );\n }\n const percent = Math.round((progress.done / progress.total) * 100);\n return (\n <div className=\"flex flex-col\">\n <SectionHeading\n trailing={\n <span className=\"font-medium text-foreground text-xs tabular-nums\">\n {progress.done}/{progress.total} done\n </span>\n }\n >\n Plan\n </SectionHeading>\n <div className=\"mx-3 mb-2 h-1 overflow-hidden rounded-full bg-muted\">\n {/* A runtime percentage is the one width a static utility cannot express. */}\n <div className=\"h-full rounded-full bg-primary transition-all\" style={{ width: `${percent}%` }} />\n </div>\n <ol className=\"flex flex-col pb-3\" aria-label=\"Plan steps\">\n {progress.steps.map((step, index) => (\n <li\n key={step.id ?? `${index}:${step.content}`}\n data-status={step.status}\n className=\"flex items-start gap-2.5 px-3 py-1.5\"\n >\n {step.status === 'pending' ? (\n // The row already carries its number; a pending marker repeating it reads \"11 11.\".\n <span aria-hidden className=\"size-[18px] shrink-0 rounded-full border border-border border-dashed\" />\n ) : (\n <PlanStepMarker status={step.status} index={index} />\n )}\n <span className=\"sr-only\">{TASK_STATUS_LABEL[step.status]}: </span>\n <span\n className={cn(\n 'min-w-0 flex-1 text-sm leading-[18px]',\n step.status === 'completed' && 'text-muted-foreground line-through',\n step.status === 'in_progress' && 'font-medium text-foreground',\n step.status === 'failed' && 'text-destructive',\n step.status === 'cancelled' && 'text-muted-foreground line-through',\n )}\n >\n <span className=\"mr-1.5 text-muted-foreground tabular-nums\">{index + 1}.</span>\n {step.content}\n </span>\n </li>\n ))}\n </ol>\n </div>\n );\n};\n\nexport const SessionTasksPane: FC = () => (\n <RequiresStatewireThread icon={ListChecksIcon}>\n <TasksPaneContent />\n </RequiresStatewireThread>\n);\n\n// ─── Shell ───────────────────────────────────────────────────────────\n\nconst SHELL_STATUS_LABEL: Record<ShellRowStatus, string> = {\n running: 'Running',\n succeeded: 'Succeeded',\n failed: 'Failed',\n unknown: 'Finished',\n};\n\nconst ShellStatusIcon: FC<{ status: ShellRowStatus }> = ({ status }) => {\n const label = SHELL_STATUS_LABEL[status];\n if (status === 'running') {\n return <LoaderIcon className=\"mt-0.5 size-3.5 shrink-0 animate-spin text-primary\" aria-label={label} />;\n }\n if (status === 'succeeded') {\n return <CheckIcon className=\"mt-0.5 size-3.5 shrink-0 text-emerald-600\" aria-label={label} />;\n }\n if (status === 'failed') {\n return <XIcon className=\"mt-0.5 size-3.5 shrink-0 text-red-600\" aria-label={label} />;\n }\n return <CircleDashedIcon className=\"mt-0.5 size-3.5 shrink-0 text-muted-foreground\" aria-label={label} />;\n};\n\nfunction shellMeta(row: ShellRow): string {\n const parts = [row.machine.label];\n if (row.exitCode !== null) parts.push(`exit ${row.exitCode}`);\n if (row.createdAt) parts.push(relativeTime(row.createdAt));\n return parts.join(' · ');\n}\n\nconst ShellRowItem: FC<{ row: ShellRow; expanded: boolean; onToggle: () => void }> = ({\n row,\n expanded,\n onToggle,\n}) => {\n const panelId = `athena-shell-${row.id}`;\n return (\n <li data-status={row.status} className=\"border-border/60 border-b last:border-b-0\">\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-controls={panelId}\n onClick={onToggle}\n className={cn(\n 'flex w-full items-start gap-2 px-3 py-2 text-left transition-colors hover:bg-muted/60',\n FOCUS_RING_CLASS,\n )}\n >\n <ShellStatusIcon status={row.status} />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate font-mono text-foreground text-xs\">\n <span className=\"text-muted-foreground\">$ </span>\n {row.firstLine || '(empty command)'}\n {row.extraLines > 0 ? (\n <span className=\"text-muted-foreground\"> (+{row.extraLines} lines)</span>\n ) : null}\n </span>\n <span className=\"block truncate text-[11px] text-muted-foreground\" title={fullTime(row.createdAt)}>\n {shellMeta(row)}\n </span>\n </span>\n </button>\n {expanded ? (\n <div id={panelId} className=\"px-3 pb-2.5\">\n <pre\n aria-label=\"Command\"\n className=\"mb-1.5 max-h-40 overflow-auto whitespace-pre-wrap break-all rounded-md border border-border/60 px-2 py-1.5 font-mono text-[11px] text-foreground\"\n >\n {row.command}\n </pre>\n <pre className=\"max-h-72 overflow-auto whitespace-pre-wrap break-all rounded-md bg-muted px-2 py-1.5 font-mono text-[11px] text-foreground\">\n {row.status === 'running' ? 'Running…' : row.output || '(no output)'}\n </pre>\n {row.outputPartial ? (\n <p className=\"pt-1 text-[11px] text-muted-foreground\">\n Output shortened — the full output is on the command's card in the chat.\n </p>\n ) : null}\n </div>\n ) : null}\n </li>\n );\n};\n\n/**\n * The commands below come from the part of the transcript the chat has\n * loaded; earlier ones arrive a page at a time, through the chat's own history\n * edge (the same page it loads when the reader scrolls up).\n */\nconst ShellHistoryFooter: FC<{ history: StatewireHistoryState; empty: boolean }> = ({\n history,\n empty,\n}) => {\n const { canLoadOlder, loading, loadOlder } = history;\n return (\n <div className=\"flex flex-col items-center gap-2 px-3 py-4 text-center\">\n <p className=\"text-[11px] text-muted-foreground\">\n {empty\n ? 'No commands in the part of this session loaded so far.'\n : 'Earlier commands are in the part of this session not loaded yet.'}\n </p>\n {canLoadOlder && loadOlder ? (\n <button\n type=\"button\"\n onClick={loadOlder}\n disabled={loading}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border border-border px-2 py-1 font-medium text-xs transition-colors hover:bg-muted disabled:opacity-60',\n FOCUS_RING_CLASS,\n )}\n >\n {loading ? <LoaderIcon className=\"size-3.5 animate-spin\" aria-hidden /> : null}\n {loading ? 'Loading earlier commands…' : 'Load earlier commands'}\n </button>\n ) : (\n <p className=\"text-[11px] text-muted-foreground\">\n The rest is further back than one view of the conversation loads.\n </p>\n )}\n </div>\n );\n};\n\nconst ShellPaneContent: FC = () => {\n const { threadId } = useSessionWorkbench();\n const messages = useAuiState((state) => state.thread.messages);\n const workspace = useSessionWorkbenchWorkspace().data ?? null;\n const history = useStatewireHistory(threadId);\n const partial = history?.hasOlder === true;\n const rows = useMemo(() => deriveShellRows({ messages, workspace }), [messages, workspace]);\n const [query, setQuery] = useState('');\n const [expanded, setExpanded] = useState<ReadonlySet<string>>(() => new Set());\n const visible = useMemo(() => filterShellRows(rows, query), [rows, query]);\n const toggle = (id: string) =>\n setExpanded((current) => {\n const next = new Set(current);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n if (rows.length === 0) {\n if (partial && history) return <ShellHistoryFooter history={history} empty />;\n return (\n <PaneEmpty icon={TerminalIcon} title=\"No commands yet\">\n Every shell command the agent runs shows here with where it ran and how it ended.\n </PaneEmpty>\n );\n }\n return (\n <div className=\"flex flex-col\">\n <div className=\"sticky top-0 z-10 border-border/60 border-b bg-background px-3 py-2\">\n <label className=\"flex items-center gap-2 rounded-md border border-border bg-background px-2 py-1 focus-within:ring-2 focus-within:ring-ring/40\">\n <SearchIcon className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n <input\n type=\"search\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder=\"Search commands\"\n aria-label=\"Search commands\"\n className=\"min-w-0 flex-1 bg-transparent text-xs outline-none placeholder:text-muted-foreground\"\n />\n </label>\n <p className=\"pt-1.5 text-[11px] text-muted-foreground\" aria-live=\"polite\">\n {query.trim()\n ? `${visible.length} of ${rows.length} commands`\n : `${rows.length} command${rows.length === 1 ? '' : 's'}`}\n {partial ? ' so far' : ''}\n </p>\n </div>\n {visible.length === 0 ? (\n <p className=\"px-3 py-6 text-center text-muted-foreground text-xs\">No command matches.</p>\n ) : (\n <ul aria-label=\"Shell commands\">\n {visible.map((row) => (\n <ShellRowItem\n key={row.id}\n row={row}\n expanded={expanded.has(row.id)}\n onToggle={() => toggle(row.id)}\n />\n ))}\n </ul>\n )}\n {partial && history ? <ShellHistoryFooter history={history} empty={false} /> : null}\n </div>\n );\n};\n\nexport const SessionShellPane: FC = () => (\n <RequiresStatewireThread icon={TerminalIcon}>\n <ShellPaneContent />\n </RequiresStatewireThread>\n);\n\n// ─── Computer ────────────────────────────────────────────────────────\n\nconst ComputerStateBadge: FC<{ assetId: string }> = ({ assetId }) => {\n const status = useAthenaComputerStatus({ assetId });\n const badge = status.data ? computerStateBadge(status.data) : null;\n if (!badge) return null;\n return (\n <span\n data-state={status.data?.state}\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border px-2 py-0.5 text-[11px] text-muted-foreground\"\n >\n <span\n aria-hidden\n className={cn(\n 'size-1.5 rounded-full',\n badge.tone === 'running' && 'bg-emerald-500',\n badge.tone === 'transition' && 'animate-pulse bg-amber-500',\n badge.tone === 'stopped' && 'bg-muted-foreground/50',\n badge.tone === 'error' && 'bg-red-500',\n )}\n />\n {badge.label}\n </span>\n );\n};\n\nconst CopySshCommand: FC<{ assetId: string }> = ({ assetId }) => {\n const ssh = useAthenaComputerSshAccess({ assetId });\n const [copied, setCopied] = useState(false);\n const command = ssh.data?.command;\n if (!command) return null;\n const copy = () => {\n void navigator.clipboard?.writeText(command).then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n });\n };\n return (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-1.5\">\n <code className=\"min-w-0 flex-1 truncate rounded-md bg-muted px-2 py-1 font-mono text-[11px] text-foreground\" title={command}>\n {command}\n </code>\n <button\n type=\"button\"\n onClick={copy}\n className={cn(\n 'inline-flex shrink-0 items-center gap-1 rounded-md border border-border px-2 py-1 font-medium text-xs transition-colors hover:bg-muted',\n FOCUS_RING_CLASS,\n )}\n >\n {copied ? <CheckIcon className=\"size-3.5\" aria-hidden /> : <CopyIcon className=\"size-3.5\" aria-hidden />}\n {copied ? 'Copied' : 'Copy SSH command'}\n </button>\n </div>\n {ssh.data?.keyAuthEnabled === false ? (\n <p className=\"text-[11px] text-muted-foreground\">\n This environment's SSH gateway takes temporary tokens only; create one from the computer in Athena.\n </p>\n ) : null}\n </div>\n );\n};\n\nfunction useAssetHref(assetId: string): string | null {\n const { appUrl, backendUrl } = useAthenaConfig();\n return useMemo(() => {\n const pageOrigin = typeof window === 'undefined' ? null : window.location.origin;\n try {\n return createAthenaSpacesUrl({\n appUrl: athenaLinkAppUrl({ appUrl, backendUrl, pageOrigin }),\n assetIds: assetId,\n });\n } catch {\n return null;\n }\n }, [appUrl, backendUrl, assetId]);\n}\n\nconst OpenInAthenaLink: FC<{ assetId: string; label?: string; compact?: boolean }> = ({\n assetId,\n label = 'Open in Athena',\n compact = false,\n}) => {\n const href = useAssetHref(assetId);\n if (!href) return null;\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={compact ? label : undefined}\n title={compact ? label : undefined}\n className={cn(\n 'inline-flex shrink-0 items-center gap-1 rounded-md font-medium text-xs transition-colors hover:bg-muted',\n compact ? 'p-1 text-muted-foreground hover:text-foreground' : 'border border-border px-2 py-1',\n FOCUS_RING_CLASS,\n )}\n >\n <ExternalLinkIcon className=\"size-3.5\" aria-hidden />\n {compact ? null : label}\n </a>\n );\n};\n\nconst ComputerCard: FC<{ computer: SessionWorkspaceAsset }> = ({ computer }) => (\n <article\n aria-label={computer.title ?? computer.assetId}\n className=\"mx-3 mt-3 flex flex-col gap-3 rounded-xl border border-border p-3\"\n >\n <div className=\"flex items-start gap-2.5\">\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground\">\n <MonitorIcon className=\"size-4\" aria-hidden />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-medium text-foreground text-sm\">{computer.title ?? computer.assetId}</p>\n <p className=\"truncate text-[11px] text-muted-foreground\">\n {computer.role === 'session_computer' ? 'Session computer' : 'Used by this session'}\n {computer.updatedAt ? ` · updated ${relativeTime(computer.updatedAt)}` : ''}\n </p>\n </div>\n <ComputerStateBadge assetId={computer.assetId} />\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <OpenInAthenaLink assetId={computer.assetId} />\n </div>\n <CopySshCommand assetId={computer.assetId} />\n </article>\n);\n\nexport const SessionComputerPane: FC = () => {\n const { isPersisted } = useSessionWorkbench();\n const workspace = useSessionWorkbenchWorkspace();\n if (!isPersisted) {\n return (\n <PaneEmpty icon={MonitorIcon} title=\"No computer yet\">\n The computer this session works on shows here once it starts.\n </PaneEmpty>\n );\n }\n if (workspace.isError) return <PaneError error={workspace.error} />;\n if (!workspace.data) return <PaneSkeleton />;\n const { primary, others } = workspaceComputers(workspace.data);\n if (!primary) {\n return (\n <PaneEmpty icon={MonitorIcon} title=\"No computer used yet\">\n When the agent runs commands on a computer, it shows here with a link and its SSH command.\n </PaneEmpty>\n );\n }\n return (\n <div className=\"flex flex-col pb-3\">\n <ComputerLiveDesktop assetId={primary.assetId} className=\"mx-3 mt-3\" />\n <ComputerCard computer={primary} />\n {others.length > 0 ? (\n <>\n <SectionHeading>Also used</SectionHeading>\n <ul aria-label=\"Other computers\">\n {others.map((computer) => (\n <li key={computer.assetId} className=\"flex items-center gap-2 px-3 py-1.5\">\n <MonitorIcon className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n <span className=\"min-w-0 flex-1 truncate text-foreground text-sm\">\n {computer.title ?? computer.assetId}\n </span>\n <OpenInAthenaLink assetId={computer.assetId} compact label={`Open ${computer.title ?? 'computer'} in Athena`} />\n </li>\n ))}\n </ul>\n </>\n ) : null}\n </div>\n );\n};\n\n// ─── Pull requests ───────────────────────────────────────────────────\n\nconst PullRequestRow: FC<{ pullRequest: ConversationPullRequest }> = ({ pullRequest }) => {\n const state = pullRequestChipState(pullRequest);\n const Icon = PR_STATE_ICON[state];\n const meta = [\n `${pullRequest.repoFullName}#${pullRequest.number}`,\n state,\n PR_CHECKS_LABEL[pullRequest.checksState],\n reviewDecisionLabel(pullRequest.reviewDecision),\n ]\n .filter(Boolean)\n .join(' · ');\n return (\n <li>\n <a\n href={pullRequest.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-pr-state={state}\n className={cn('flex items-start gap-2.5 px-3 py-2 transition-colors hover:bg-muted/60', FOCUS_RING_CLASS)}\n >\n <Icon className={cn('mt-0.5 size-4 shrink-0', PR_STATE_CLASS[state])} aria-hidden />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-foreground text-sm leading-snug\">\n {pullRequest.title || `#${pullRequest.number}`}\n </span>\n <span className=\"block truncate text-[11px] text-muted-foreground\">{meta}</span>\n </span>\n <ExternalLinkIcon className=\"mt-0.5 size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n </a>\n </li>\n );\n};\n\nexport const SessionPullRequestsPane: FC = () => {\n const { threadId, isPersisted } = useSessionWorkbench();\n const list = useAthenaStatewireThreadList();\n const attention = useAthenaSessionAttention(threadId ?? undefined);\n if (!list) {\n return (\n <PaneEmpty icon={GitPullRequestIcon} title=\"Pull requests need the session list\">\n Mount the provider with enableThreadList to see the pull requests a session opened.\n </PaneEmpty>\n );\n }\n const pullRequests = isPersisted ? (attention?.pullRequests ?? []) : [];\n if (attention?.pullRequests === null && isPersisted) {\n return (\n <PaneEmpty icon={GitPullRequestIcon} title=\"Pull requests unavailable\">\n GitHub could not be read for this session right now.\n </PaneEmpty>\n );\n }\n if (pullRequests.length === 0) {\n return (\n <PaneEmpty icon={GitPullRequestIcon} title=\"No pull requests\">\n Pull requests the agent opens show here with their checks and review state.\n </PaneEmpty>\n );\n }\n const ordered = orderedPullRequests(pullRequests);\n return (\n <div className=\"flex flex-col pb-2\">\n <SectionHeading\n trailing={<span className=\"text-muted-foreground text-xs tabular-nums\">{ordered.length}</span>}\n >\n Pull requests\n </SectionHeading>\n <ul aria-label=\"Pull requests\">\n {ordered.map((pullRequest) => (\n <PullRequestRow key={pullRequest.url} pullRequest={pullRequest} />\n ))}\n </ul>\n </div>\n );\n};\n\n// ─── Attachments ─────────────────────────────────────────────────────\n\nconst ASSET_ICON: Record<string, FC<{ className?: string }>> = {\n spreadsheet: FileSpreadsheetIcon,\n document: FileTextIcon,\n presentation: PresentationIcon,\n presentation_pptx_studio: PresentationIcon,\n pptx: PresentationIcon,\n notebook: BookOpenIcon,\n image: ImageIcon,\n folder: FolderIcon,\n markdown: FileTextIcon,\n pdf: FileTextIcon,\n txt: FileTextIcon,\n};\n\nconst AttachmentRow: FC<{ asset: SessionWorkspaceAsset; canOpenHere: boolean }> = ({\n asset,\n canOpenHere,\n}) => {\n const openAsset = useAssetPanelStore((state) => state.openAsset);\n const Icon = ASSET_ICON[asset.assetType] ?? FileIcon;\n const panelType: AssetPanelType | null = assetPanelTypeOf(asset.assetType);\n const title = asset.title ?? asset.assetId;\n const meta = [\n assetTypeLabel(asset.assetType),\n asset.updatedAt ? `updated ${relativeTime(asset.updatedAt)}` : null,\n ]\n .filter(Boolean)\n .join(' · ');\n const body = (\n <>\n <Icon className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-foreground text-sm\">{title}</span>\n <span className=\"block truncate text-[11px] text-muted-foreground\" title={fullTime(asset.updatedAt)}>\n {meta}\n </span>\n </span>\n </>\n );\n return (\n <li className=\"flex items-start gap-1 pr-2\">\n {canOpenHere && panelType ? (\n <button\n type=\"button\"\n onClick={() => openAsset(asset.assetId, { name: title, type: panelType })}\n className={cn(\n 'flex min-w-0 flex-1 items-start gap-2.5 px-3 py-2 text-left transition-colors hover:bg-muted/60',\n FOCUS_RING_CLASS,\n )}\n >\n {body}\n </button>\n ) : (\n <div className=\"flex min-w-0 flex-1 items-start gap-2.5 px-3 py-2\">{body}</div>\n )}\n <span className=\"pt-1.5\">\n <OpenInAthenaLink assetId={asset.assetId} compact label={`Open ${title} in Athena`} />\n </span>\n </li>\n );\n};\n\nexport const SessionAttachmentsPane: FC = () => {\n const { isPersisted } = useSessionWorkbench();\n const workspace = useSessionWorkbenchWorkspace();\n const canOpenHere = useAssetPanelStore((state) => state.assetPanelHostCount > 0);\n if (!isPersisted) {\n return (\n <PaneEmpty icon={PaperclipIcon} title=\"No files yet\">\n Documents, sheets and decks the agent creates or edits show here.\n </PaneEmpty>\n );\n }\n if (workspace.isError) return <PaneError error={workspace.error} />;\n if (!workspace.data) return <PaneSkeleton />;\n const { assets } = workspace.data;\n if (assets.length === 0) {\n return (\n <PaneEmpty icon={PaperclipIcon} title=\"No files yet\">\n Documents, sheets and decks the agent creates or edits show here.\n </PaneEmpty>\n );\n }\n return (\n <div className=\"flex flex-col pb-2\">\n <SectionHeading\n trailing={<span className=\"text-muted-foreground text-xs tabular-nums\">{assets.length}</span>}\n >\n Created or edited\n </SectionHeading>\n <ul aria-label=\"Session files\">\n {assets.map((asset) => (\n <AttachmentRow key={asset.assetId} asset={asset} canOpenHere={canOpenHere} />\n ))}\n </ul>\n </div>\n );\n};\n\n// ─── Registry ────────────────────────────────────────────────────────\n\nexport const SESSION_WORKBENCH_TASKS_PANE: SessionWorkbenchPane = {\n id: 'tasks',\n title: 'Tasks',\n description: \"Follow the agent's plan step by step\",\n icon: ListChecksIcon,\n render: () => <SessionTasksPane />,\n};\n\nexport const SESSION_WORKBENCH_SHELL_PANE: SessionWorkbenchPane = {\n id: 'shell',\n title: 'Shell',\n description: 'Commands the agent ran and their output',\n icon: TerminalIcon,\n render: () => <SessionShellPane />,\n};\n\nexport const SESSION_WORKBENCH_COMPUTER_PANE: SessionWorkbenchPane = {\n id: 'computer',\n title: 'Computer',\n description: 'The machine this session works on, and how to reach it',\n icon: MonitorIcon,\n render: () => <SessionComputerPane />,\n};\n\nexport const SESSION_WORKBENCH_PULL_REQUESTS_PANE: SessionWorkbenchPane = {\n id: 'pull-requests',\n title: 'Pull requests',\n description: 'Pull requests this session opened, with checks and reviews',\n icon: GitPullRequestIcon,\n render: () => <SessionPullRequestsPane />,\n};\n\nexport const SESSION_WORKBENCH_ATTACHMENTS_PANE: SessionWorkbenchPane = {\n id: 'attachments',\n title: 'Attachments',\n description: 'Files and assets this session created or edited',\n icon: PaperclipIcon,\n render: () => <SessionAttachmentsPane />,\n};\n\n/** The built-in panes, in \"+\" menu order. Spread it to add your own. */\nexport const DEFAULT_SESSION_WORKBENCH_PANES: readonly SessionWorkbenchPane[] = [\n SESSION_WORKBENCH_TASKS_PANE,\n SESSION_WORKBENCH_SHELL_PANE,\n SESSION_WORKBENCH_COMPUTER_PANE,\n SESSION_WORKBENCH_PULL_REQUESTS_PANE,\n SESSION_WORKBENCH_ATTACHMENTS_PANE,\n];\n\n/** The panes a thread opens with until the person changes its tabs. */\nexport const DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS: readonly string[] = [\n SESSION_WORKBENCH_TASKS_PANE.id,\n SESSION_WORKBENCH_SHELL_PANE.id,\n SESSION_WORKBENCH_COMPUTER_PANE.id,\n];\n"],"names":["jsxs","jsx","AlertCircleIcon","useAuiState","hasStatewireThreadExtras","useStatewireState","readDeepAgentStreamValues","useMemo","taskProgress","deriveTaskSteps","ListChecksIcon","PlanStepMarker","cn","LoaderIcon","CheckIcon","XIcon","CircleDashedIcon","relativeTime","useSessionWorkbench","useSessionWorkbenchWorkspace","useStatewireHistory","deriveShellRows","useState","filterShellRows","TerminalIcon","SearchIcon","useAthenaComputerStatus","computerStateBadge","useAthenaComputerSshAccess","_a","CopyIcon","useAthenaConfig","createAthenaSpacesUrl","athenaLinkAppUrl","ExternalLinkIcon","MonitorIcon","workspaceComputers","ComputerLiveDesktop","Fragment","pullRequestChipState","PR_STATE_ICON","PR_CHECKS_LABEL","reviewDecisionLabel","PR_STATE_CLASS","useAthenaStatewireThreadList","useAthenaSessionAttention","GitPullRequestIcon","orderedPullRequests","FileSpreadsheetIcon","FileTextIcon","PresentationIcon","BookOpenIcon","ImageIcon","FolderIcon","useAssetPanelStore","FileIcon","assetPanelTypeOf","assetTypeLabel","PaperclipIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session-workbench-panes.cjs","sources":["../../src/workbench/session-workbench-panes.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * The built-in panes of `SessionWorkbench` — Tasks, Shell, Computer, Pull\n * requests and Attachments. Each reads one source:\n *\n * - Tasks: the thread state's `todos` channel (the deepagents plan), else the\n * newest `write_todos` call in the loaded transcript.\n * - Shell: every `execute` call in the loaded transcript; while the thread has\n * older history the chat has not loaded, it says so and loads the next page\n * on request (`StatewireHistoryContext`).\n * - Computer / Attachments: the session's workspace\n * (`GET /api/conversations/threads/{id}/workspace`), plus the computer's\n * status and SSH target; the Computer pane also shows the computer's screen\n * live (`ComputerLiveDesktop`).\n * - Pull requests: the thread list's live pull-request state for the session.\n */\nimport { useAuiState } from '@assistant-ui/react';\nimport { useStatewireState } from '@assistant-ui/react-statewire';\nimport {\n type ConversationPullRequest,\n hasStatewireThreadExtras,\n readDeepAgentStreamValues,\n} from '@athenaintel/agent-runtime';\nimport {\n AlertCircleIcon,\n BookOpenIcon,\n CheckIcon,\n CircleDashedIcon,\n CopyIcon,\n ExternalLinkIcon,\n FileIcon,\n FileSpreadsheetIcon,\n FileTextIcon,\n FolderIcon,\n GitPullRequestIcon,\n ImageIcon,\n ListChecksIcon,\n LoaderIcon,\n MonitorIcon,\n PaperclipIcon,\n PresentationIcon,\n SearchIcon,\n TerminalIcon,\n XIcon,\n} from 'lucide-react';\nimport { type FC, type ReactNode, useMemo, useState } from 'react';\nimport { type AssetType as AssetPanelType, useAssetPanelStore } from '../assets/asset-panel-store';\nimport { athenaLinkAppUrl, createAthenaSpacesUrl } from '../lib/athena-urls';\nimport { cn } from '../lib/utils';\nimport { useAthenaConfig } from '../provider/AthenaContext';\nimport {\n type StatewireHistoryState,\n useStatewireHistory,\n} from '../provider/statewire-history-context';\nimport { PR_CHECKS_LABEL, PR_STATE_CLASS, PR_STATE_ICON } from '../threads/pull-request-display';\nimport {\n orderedPullRequests,\n pullRequestChipState,\n relativeTime,\n} from '../threads/session-list-model';\nimport { useAthenaStatewireThreadList } from '../threads/statewire-thread-list';\nimport { useAthenaSessionAttention } from '../threads/use-athena-session-attention';\nimport { PlanStepMarker, type PlanStepStatus } from '../tools/write-todos-tool-ui';\nimport {\n type SessionWorkbenchPane,\n useSessionWorkbench,\n useSessionWorkbenchWorkspace,\n} from './session-workbench-context';\nimport {\n assetPanelTypeOf,\n assetTypeLabel,\n computerStateBadge,\n deriveShellRows,\n deriveTaskSteps,\n filterShellRows,\n reviewDecisionLabel,\n type ShellRow,\n type ShellRowStatus,\n taskProgress,\n workspaceComputers,\n} from './session-workbench-model';\nimport { ComputerLiveDesktop } from './ComputerLiveDesktop';\nimport type { SessionWorkspaceAsset } from './session-workspace-api';\nimport { useAthenaComputerSshAccess, useAthenaComputerStatus } from './use-session-workspace';\n\n// ─── Shared pieces ───────────────────────────────────────────────────\n\nconst FOCUS_RING_CLASS =\n 'outline-none focus-visible:ring-2 focus-visible:ring-ring/60 focus-visible:ring-offset-0';\n\nconst PaneEmpty: FC<{\n icon: FC<{ className?: string }>;\n title: string;\n children?: ReactNode;\n}> = ({ icon: Icon, title, children }) => (\n <div className=\"flex h-full min-h-40 flex-col items-center justify-center gap-2 px-6 py-10 text-center\">\n <Icon className=\"size-5 text-muted-foreground/70\" />\n <p className=\"font-medium text-foreground text-sm\">{title}</p>\n {children ? <p className=\"max-w-64 text-muted-foreground text-xs leading-snug\">{children}</p> : null}\n </div>\n);\n\nconst PaneError: FC<{ error: Error }> = ({ error }) => (\n <div role=\"alert\" className=\"m-3 flex items-start gap-2 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-red-900 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0\" aria-hidden />\n <span className=\"min-w-0 flex-1 break-words\">{error.message}</span>\n </div>\n);\n\nconst PaneSkeleton: FC = () => (\n <div className=\"flex flex-col gap-2 p-3\" aria-busy=\"true\" aria-label=\"Loading\">\n {[0, 1, 2].map((row) => (\n <div key={row} className=\"h-10 animate-pulse rounded-lg bg-muted\" />\n ))}\n </div>\n);\n\nconst SectionHeading: FC<{ children: ReactNode; trailing?: ReactNode }> = ({ children, trailing }) => (\n <div className=\"flex items-center justify-between gap-2 px-3 pt-3 pb-1.5\">\n <h3 className=\"font-medium text-[11px] text-muted-foreground uppercase tracking-wide\">{children}</h3>\n {trailing}\n </div>\n);\n\n/** The `title` tooltip for an ISO time: the full local date and time. */\nfunction fullTime(iso: string | null): string | undefined {\n if (!iso) return undefined;\n const time = Date.parse(iso);\n return Number.isNaN(time) ? undefined : new Date(time).toLocaleString();\n}\n\n/** Statewire-only panes read the transcript and thread state; elsewhere they say so. */\nconst RequiresStatewireThread: FC<{ children: ReactNode; icon: FC<{ className?: string }> }> = ({\n children,\n icon,\n}) => {\n const extras = useAuiState((state) => state.thread.extras);\n if (!hasStatewireThreadExtras(extras)) {\n return <PaneEmpty icon={icon} title=\"No live session\">Open a session to see this pane.</PaneEmpty>;\n }\n return <>{children}</>;\n};\n\n// ─── Tasks ───────────────────────────────────────────────────────────\n\nconst TASK_STATUS_LABEL: Record<PlanStepStatus, string> = {\n pending: 'To do',\n in_progress: 'In progress',\n completed: 'Done',\n failed: 'Failed',\n cancelled: 'Cancelled',\n};\n\nconst TasksPaneContent: FC = () => {\n const stateTodos = useStatewireState((state) => readDeepAgentStreamValues(state).todos);\n const messages = useAuiState((state) => state.thread.messages);\n const progress = useMemo(\n () => taskProgress(deriveTaskSteps({ stateTodos, messages })),\n [stateTodos, messages],\n );\n if (progress.total === 0) {\n return (\n <PaneEmpty icon={ListChecksIcon} title=\"No plan yet\">\n When the agent writes a plan, its steps show here as it works through them.\n </PaneEmpty>\n );\n }\n const percent = Math.round((progress.done / progress.total) * 100);\n return (\n <div className=\"flex flex-col\">\n <SectionHeading\n trailing={\n <span className=\"font-medium text-foreground text-xs tabular-nums\">\n {progress.done}/{progress.total} done\n </span>\n }\n >\n Plan\n </SectionHeading>\n <div className=\"mx-3 mb-2 h-1 overflow-hidden rounded-full bg-muted\">\n {/* A runtime percentage is the one width a static utility cannot express. */}\n <div className=\"h-full rounded-full bg-primary transition-all\" style={{ width: `${percent}%` }} />\n </div>\n <ol className=\"flex flex-col pb-3\" aria-label=\"Plan steps\">\n {progress.steps.map((step, index) => (\n <li\n key={step.id ?? `${index}:${step.content}`}\n data-status={step.status}\n className=\"flex items-start gap-2.5 px-3 py-1.5\"\n >\n {step.status === 'pending' ? (\n // The row already carries its number; a pending marker repeating it reads \"11 11.\".\n <span aria-hidden className=\"size-[18px] shrink-0 rounded-full border border-border border-dashed\" />\n ) : (\n <PlanStepMarker status={step.status} index={index} />\n )}\n <span className=\"sr-only\">{TASK_STATUS_LABEL[step.status]}: </span>\n <span\n className={cn(\n 'min-w-0 flex-1 text-sm leading-[18px]',\n step.status === 'completed' && 'text-muted-foreground line-through',\n step.status === 'in_progress' && 'font-medium text-foreground',\n step.status === 'failed' && 'text-destructive',\n step.status === 'cancelled' && 'text-muted-foreground line-through',\n )}\n >\n <span className=\"mr-1.5 text-muted-foreground tabular-nums\">{index + 1}.</span>\n {step.content}\n </span>\n </li>\n ))}\n </ol>\n </div>\n );\n};\n\nexport const SessionTasksPane: FC = () => (\n <RequiresStatewireThread icon={ListChecksIcon}>\n <TasksPaneContent />\n </RequiresStatewireThread>\n);\n\n// ─── Shell ───────────────────────────────────────────────────────────\n\nconst SHELL_STATUS_LABEL: Record<ShellRowStatus, string> = {\n running: 'Running',\n succeeded: 'Succeeded',\n failed: 'Failed',\n unknown: 'Finished',\n};\n\nconst ShellStatusIcon: FC<{ status: ShellRowStatus }> = ({ status }) => {\n const label = SHELL_STATUS_LABEL[status];\n if (status === 'running') {\n return <LoaderIcon className=\"mt-0.5 size-3.5 shrink-0 animate-spin text-primary\" aria-label={label} />;\n }\n if (status === 'succeeded') {\n return <CheckIcon className=\"mt-0.5 size-3.5 shrink-0 text-emerald-600\" aria-label={label} />;\n }\n if (status === 'failed') {\n return <XIcon className=\"mt-0.5 size-3.5 shrink-0 text-red-600\" aria-label={label} />;\n }\n return <CircleDashedIcon className=\"mt-0.5 size-3.5 shrink-0 text-muted-foreground\" aria-label={label} />;\n};\n\nfunction shellMeta(row: ShellRow): string {\n const parts = [row.machine.label];\n if (row.exitCode !== null) parts.push(`exit ${row.exitCode}`);\n if (row.createdAt) parts.push(relativeTime(row.createdAt));\n return parts.join(' · ');\n}\n\nconst ShellRowItem: FC<{ row: ShellRow; expanded: boolean; onToggle: () => void }> = ({\n row,\n expanded,\n onToggle,\n}) => {\n const panelId = `athena-shell-${row.id}`;\n return (\n <li data-status={row.status} className=\"border-border/60 border-b last:border-b-0\">\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-controls={panelId}\n onClick={onToggle}\n className={cn(\n 'flex w-full items-start gap-2 px-3 py-2 text-left transition-colors hover:bg-muted/60',\n FOCUS_RING_CLASS,\n )}\n >\n <ShellStatusIcon status={row.status} />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate font-mono text-foreground text-xs\">\n <span className=\"text-muted-foreground\">$ </span>\n {row.firstLine || '(empty command)'}\n {row.extraLines > 0 ? (\n <span className=\"text-muted-foreground\"> (+{row.extraLines} lines)</span>\n ) : null}\n </span>\n <span className=\"block truncate text-[11px] text-muted-foreground\" title={fullTime(row.createdAt)}>\n {shellMeta(row)}\n </span>\n </span>\n </button>\n {expanded ? (\n <div id={panelId} className=\"px-3 pb-2.5\">\n <pre\n aria-label=\"Command\"\n className=\"mb-1.5 max-h-40 overflow-auto whitespace-pre-wrap break-all rounded-md border border-border/60 px-2 py-1.5 font-mono text-[11px] text-foreground\"\n >\n {row.command}\n </pre>\n <pre className=\"max-h-72 overflow-auto whitespace-pre-wrap break-all rounded-md bg-muted px-2 py-1.5 font-mono text-[11px] text-foreground\">\n {row.status === 'running' ? 'Running…' : row.output || '(no output)'}\n </pre>\n {row.outputPartial ? (\n <p className=\"pt-1 text-[11px] text-muted-foreground\">\n Output shortened — the full output is on the command's card in the chat.\n </p>\n ) : null}\n </div>\n ) : null}\n </li>\n );\n};\n\n/**\n * The commands below come from the part of the transcript the chat has\n * loaded; earlier ones arrive a page at a time, through the chat's own history\n * edge (the same page it loads when the reader scrolls up).\n */\nconst ShellHistoryFooter: FC<{ history: StatewireHistoryState; empty: boolean }> = ({\n history,\n empty,\n}) => {\n const { canLoadOlder, loading, loadOlder } = history;\n return (\n <div className=\"flex flex-col items-center gap-2 px-3 py-4 text-center\">\n <p className=\"text-[11px] text-muted-foreground\">\n {empty\n ? 'No commands in the part of this session loaded so far.'\n : 'Earlier commands are in the part of this session not loaded yet.'}\n </p>\n {canLoadOlder && loadOlder ? (\n <button\n type=\"button\"\n onClick={loadOlder}\n disabled={loading}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md border border-border px-2 py-1 font-medium text-xs transition-colors hover:bg-muted disabled:opacity-60',\n FOCUS_RING_CLASS,\n )}\n >\n {loading ? <LoaderIcon className=\"size-3.5 animate-spin\" aria-hidden /> : null}\n {loading ? 'Loading earlier commands…' : 'Load earlier commands'}\n </button>\n ) : (\n <p className=\"text-[11px] text-muted-foreground\">\n The rest is further back than one view of the conversation loads.\n </p>\n )}\n </div>\n );\n};\n\nconst ShellPaneContent: FC = () => {\n const { threadId } = useSessionWorkbench();\n const messages = useAuiState((state) => state.thread.messages);\n const workspace = useSessionWorkbenchWorkspace().data ?? null;\n const history = useStatewireHistory(threadId);\n const partial = history?.hasOlder === true;\n const rows = useMemo(() => deriveShellRows({ messages, workspace }), [messages, workspace]);\n const [query, setQuery] = useState('');\n const [expanded, setExpanded] = useState<ReadonlySet<string>>(() => new Set());\n const visible = useMemo(() => filterShellRows(rows, query), [rows, query]);\n const toggle = (id: string) =>\n setExpanded((current) => {\n const next = new Set(current);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n if (rows.length === 0) {\n if (partial && history) return <ShellHistoryFooter history={history} empty />;\n return (\n <PaneEmpty icon={TerminalIcon} title=\"No commands yet\">\n Every shell command the agent runs shows here with where it ran and how it ended.\n </PaneEmpty>\n );\n }\n return (\n <div className=\"flex flex-col\">\n <div className=\"sticky top-0 z-10 border-border/60 border-b bg-background px-3 py-2\">\n <label className=\"flex items-center gap-2 rounded-md border border-border bg-background px-2 py-1 focus-within:ring-2 focus-within:ring-ring/40\">\n <SearchIcon className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n <input\n type=\"search\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder=\"Search commands\"\n aria-label=\"Search commands\"\n className=\"min-w-0 flex-1 bg-transparent text-xs outline-none placeholder:text-muted-foreground\"\n />\n </label>\n <p className=\"pt-1.5 text-[11px] text-muted-foreground\" aria-live=\"polite\">\n {query.trim()\n ? `${visible.length} of ${rows.length} commands`\n : `${rows.length} command${rows.length === 1 ? '' : 's'}`}\n {partial ? ' so far' : ''}\n </p>\n </div>\n {visible.length === 0 ? (\n <p className=\"px-3 py-6 text-center text-muted-foreground text-xs\">No command matches.</p>\n ) : (\n <ul aria-label=\"Shell commands\">\n {visible.map((row) => (\n <ShellRowItem\n key={row.id}\n row={row}\n expanded={expanded.has(row.id)}\n onToggle={() => toggle(row.id)}\n />\n ))}\n </ul>\n )}\n {partial && history ? <ShellHistoryFooter history={history} empty={false} /> : null}\n </div>\n );\n};\n\nexport const SessionShellPane: FC = () => (\n <RequiresStatewireThread icon={TerminalIcon}>\n <ShellPaneContent />\n </RequiresStatewireThread>\n);\n\n// ─── Computer ────────────────────────────────────────────────────────\n\nconst ComputerStateBadge: FC<{ assetId: string }> = ({ assetId }) => {\n const status = useAthenaComputerStatus({ assetId });\n const badge = status.data ? computerStateBadge(status.data) : null;\n if (!badge) return null;\n return (\n <span\n data-state={status.data?.state}\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border px-2 py-0.5 text-[11px] text-muted-foreground\"\n >\n <span\n aria-hidden\n className={cn(\n 'size-1.5 rounded-full',\n badge.tone === 'running' && 'bg-emerald-500',\n badge.tone === 'transition' && 'animate-pulse bg-amber-500',\n badge.tone === 'stopped' && 'bg-muted-foreground/50',\n badge.tone === 'error' && 'bg-red-500',\n )}\n />\n {badge.label}\n </span>\n );\n};\n\nconst CopySshCommand: FC<{ assetId: string }> = ({ assetId }) => {\n const ssh = useAthenaComputerSshAccess({ assetId });\n const [copied, setCopied] = useState(false);\n const command = ssh.data?.command;\n if (!command) return null;\n const copy = () => {\n void navigator.clipboard?.writeText(command).then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n });\n };\n return (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-1.5\">\n <code className=\"min-w-0 flex-1 truncate rounded-md bg-muted px-2 py-1 font-mono text-[11px] text-foreground\" title={command}>\n {command}\n </code>\n <button\n type=\"button\"\n onClick={copy}\n className={cn(\n 'inline-flex shrink-0 items-center gap-1 rounded-md border border-border px-2 py-1 font-medium text-xs transition-colors hover:bg-muted',\n FOCUS_RING_CLASS,\n )}\n >\n {copied ? <CheckIcon className=\"size-3.5\" aria-hidden /> : <CopyIcon className=\"size-3.5\" aria-hidden />}\n {copied ? 'Copied' : 'Copy SSH command'}\n </button>\n </div>\n {ssh.data?.keyAuthEnabled === false ? (\n <p className=\"text-[11px] text-muted-foreground\">\n This environment's SSH gateway takes temporary tokens only; create one from the computer in Athena.\n </p>\n ) : null}\n </div>\n );\n};\n\nfunction useAssetHref(assetId: string): string | null {\n const { appUrl, backendUrl } = useAthenaConfig();\n return useMemo(() => {\n const pageOrigin = typeof window === 'undefined' ? null : window.location.origin;\n try {\n return createAthenaSpacesUrl({\n appUrl: athenaLinkAppUrl({ appUrl, backendUrl, pageOrigin }),\n assetIds: assetId,\n });\n } catch {\n return null;\n }\n }, [appUrl, backendUrl, assetId]);\n}\n\nconst OpenInAthenaLink: FC<{ assetId: string; label?: string; compact?: boolean }> = ({\n assetId,\n label = 'Open in Athena',\n compact = false,\n}) => {\n const href = useAssetHref(assetId);\n if (!href) return null;\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={compact ? label : undefined}\n title={compact ? label : undefined}\n className={cn(\n 'inline-flex shrink-0 items-center gap-1 rounded-md font-medium text-xs transition-colors hover:bg-muted',\n compact ? 'p-1 text-muted-foreground hover:text-foreground' : 'border border-border px-2 py-1',\n FOCUS_RING_CLASS,\n )}\n >\n <ExternalLinkIcon className=\"size-3.5\" aria-hidden />\n {compact ? null : label}\n </a>\n );\n};\n\nconst ComputerCard: FC<{ computer: SessionWorkspaceAsset }> = ({ computer }) => (\n <article\n aria-label={computer.title ?? computer.assetId}\n className=\"mx-3 mt-3 flex flex-col gap-3 rounded-xl border border-border p-3\"\n >\n <div className=\"flex items-start gap-2.5\">\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground\">\n <MonitorIcon className=\"size-4\" aria-hidden />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-medium text-foreground text-sm\">{computer.title ?? computer.assetId}</p>\n <p className=\"truncate text-[11px] text-muted-foreground\">\n {computer.role === 'session_computer' ? 'Session computer' : 'Used by this session'}\n {computer.updatedAt ? ` · updated ${relativeTime(computer.updatedAt)}` : ''}\n </p>\n </div>\n <ComputerStateBadge assetId={computer.assetId} />\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <OpenInAthenaLink assetId={computer.assetId} />\n </div>\n <CopySshCommand assetId={computer.assetId} />\n </article>\n);\n\nexport const SessionComputerPane: FC = () => {\n const { isPersisted } = useSessionWorkbench();\n const workspace = useSessionWorkbenchWorkspace();\n if (!isPersisted) {\n return (\n <PaneEmpty icon={MonitorIcon} title=\"No computer yet\">\n The computer this session works on shows here once it starts.\n </PaneEmpty>\n );\n }\n if (workspace.isError) return <PaneError error={workspace.error} />;\n if (!workspace.data) return <PaneSkeleton />;\n const { primary, others } = workspaceComputers(workspace.data);\n if (!primary) {\n return (\n <PaneEmpty icon={MonitorIcon} title=\"No computer used yet\">\n When the agent runs commands on a computer, it shows here with a link and its SSH command.\n </PaneEmpty>\n );\n }\n return (\n <div className=\"flex flex-col pb-3\">\n <ComputerLiveDesktop assetId={primary.assetId} className=\"mx-3 mt-3\" />\n <ComputerCard computer={primary} />\n {others.length > 0 ? (\n <>\n <SectionHeading>Also used</SectionHeading>\n <ul aria-label=\"Other computers\">\n {others.map((computer) => (\n <li key={computer.assetId} className=\"flex items-center gap-2 px-3 py-1.5\">\n <MonitorIcon className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n <span className=\"min-w-0 flex-1 truncate text-foreground text-sm\">\n {computer.title ?? computer.assetId}\n </span>\n <OpenInAthenaLink assetId={computer.assetId} compact label={`Open ${computer.title ?? 'computer'} in Athena`} />\n </li>\n ))}\n </ul>\n </>\n ) : null}\n </div>\n );\n};\n\n// ─── Pull requests ───────────────────────────────────────────────────\n\nconst PullRequestRow: FC<{ pullRequest: ConversationPullRequest }> = ({ pullRequest }) => {\n const state = pullRequestChipState(pullRequest);\n const Icon = PR_STATE_ICON[state];\n const meta = [\n `${pullRequest.repoFullName}#${pullRequest.number}`,\n state,\n PR_CHECKS_LABEL[pullRequest.checksState],\n reviewDecisionLabel(pullRequest.reviewDecision),\n ]\n .filter(Boolean)\n .join(' · ');\n return (\n <li>\n <a\n href={pullRequest.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-pr-state={state}\n className={cn('flex items-start gap-2.5 px-3 py-2 transition-colors hover:bg-muted/60', FOCUS_RING_CLASS)}\n >\n <Icon className={cn('mt-0.5 size-4 shrink-0', PR_STATE_CLASS[state])} aria-hidden />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-foreground text-sm leading-snug\">\n {pullRequest.title || `#${pullRequest.number}`}\n </span>\n <span className=\"block truncate text-[11px] text-muted-foreground\">{meta}</span>\n </span>\n <ExternalLinkIcon className=\"mt-0.5 size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n </a>\n </li>\n );\n};\n\nexport const SessionPullRequestsPane: FC = () => {\n const { threadId, isPersisted } = useSessionWorkbench();\n const list = useAthenaStatewireThreadList();\n const attention = useAthenaSessionAttention(threadId ?? undefined);\n if (!list) {\n return (\n <PaneEmpty icon={GitPullRequestIcon} title=\"Pull requests need the session list\">\n Mount the provider with enableThreadList to see the pull requests a session opened.\n </PaneEmpty>\n );\n }\n const pullRequests = isPersisted ? (attention?.pullRequests ?? []) : [];\n if (attention?.pullRequests === null && isPersisted) {\n return (\n <PaneEmpty icon={GitPullRequestIcon} title=\"Pull requests unavailable\">\n GitHub could not be read for this session right now.\n </PaneEmpty>\n );\n }\n if (pullRequests.length === 0) {\n return (\n <PaneEmpty icon={GitPullRequestIcon} title=\"No pull requests\">\n Pull requests the agent opens show here with their checks and review state.\n </PaneEmpty>\n );\n }\n const ordered = orderedPullRequests(pullRequests);\n return (\n <div className=\"flex flex-col pb-2\">\n <SectionHeading\n trailing={<span className=\"text-muted-foreground text-xs tabular-nums\">{ordered.length}</span>}\n >\n Pull requests\n </SectionHeading>\n <ul aria-label=\"Pull requests\">\n {ordered.map((pullRequest) => (\n <PullRequestRow key={pullRequest.url} pullRequest={pullRequest} />\n ))}\n </ul>\n </div>\n );\n};\n\n// ─── Attachments ─────────────────────────────────────────────────────\n\nconst ASSET_ICON: Record<string, FC<{ className?: string }>> = {\n spreadsheet: FileSpreadsheetIcon,\n document: FileTextIcon,\n presentation: PresentationIcon,\n presentation_pptx_studio: PresentationIcon,\n pptx: PresentationIcon,\n notebook: BookOpenIcon,\n image: ImageIcon,\n folder: FolderIcon,\n markdown: FileTextIcon,\n pdf: FileTextIcon,\n txt: FileTextIcon,\n};\n\nconst AttachmentRow: FC<{ asset: SessionWorkspaceAsset; canOpenHere: boolean }> = ({\n asset,\n canOpenHere,\n}) => {\n const openAsset = useAssetPanelStore((state) => state.openAsset);\n const Icon = ASSET_ICON[asset.assetType] ?? FileIcon;\n const panelType: AssetPanelType | null = assetPanelTypeOf(asset.assetType);\n const title = asset.title ?? asset.assetId;\n const meta = [\n assetTypeLabel(asset.assetType),\n asset.updatedAt ? `updated ${relativeTime(asset.updatedAt)}` : null,\n ]\n .filter(Boolean)\n .join(' · ');\n const body = (\n <>\n <Icon className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-foreground text-sm\">{title}</span>\n <span className=\"block truncate text-[11px] text-muted-foreground\" title={fullTime(asset.updatedAt)}>\n {meta}\n </span>\n </span>\n </>\n );\n return (\n <li className=\"flex items-start gap-1 pr-2\">\n {canOpenHere && panelType ? (\n <button\n type=\"button\"\n onClick={() => openAsset(asset.assetId, { name: title, type: panelType })}\n className={cn(\n 'flex min-w-0 flex-1 items-start gap-2.5 px-3 py-2 text-left transition-colors hover:bg-muted/60',\n FOCUS_RING_CLASS,\n )}\n >\n {body}\n </button>\n ) : (\n <div className=\"flex min-w-0 flex-1 items-start gap-2.5 px-3 py-2\">{body}</div>\n )}\n <span className=\"pt-1.5\">\n <OpenInAthenaLink assetId={asset.assetId} compact label={`Open ${title} in Athena`} />\n </span>\n </li>\n );\n};\n\nexport const SessionAttachmentsPane: FC = () => {\n const { isPersisted } = useSessionWorkbench();\n const workspace = useSessionWorkbenchWorkspace();\n const canOpenHere = useAssetPanelStore((state) => state.assetPanelHostCount > 0);\n if (!isPersisted) {\n return (\n <PaneEmpty icon={PaperclipIcon} title=\"No files yet\">\n Documents, sheets and decks the agent creates or edits show here.\n </PaneEmpty>\n );\n }\n if (workspace.isError) return <PaneError error={workspace.error} />;\n if (!workspace.data) return <PaneSkeleton />;\n const { assets } = workspace.data;\n if (assets.length === 0) {\n return (\n <PaneEmpty icon={PaperclipIcon} title=\"No files yet\">\n Documents, sheets and decks the agent creates or edits show here.\n </PaneEmpty>\n );\n }\n return (\n <div className=\"flex flex-col pb-2\">\n <SectionHeading\n trailing={<span className=\"text-muted-foreground text-xs tabular-nums\">{assets.length}</span>}\n >\n Created or edited\n </SectionHeading>\n <ul aria-label=\"Session files\">\n {assets.map((asset) => (\n <AttachmentRow key={asset.assetId} asset={asset} canOpenHere={canOpenHere} />\n ))}\n </ul>\n </div>\n );\n};\n\n// ─── Registry ────────────────────────────────────────────────────────\n\nexport const SESSION_WORKBENCH_TASKS_PANE: SessionWorkbenchPane = {\n id: 'tasks',\n title: 'Tasks',\n description: \"Follow the agent's plan step by step\",\n icon: ListChecksIcon,\n render: () => <SessionTasksPane />,\n};\n\nexport const SESSION_WORKBENCH_SHELL_PANE: SessionWorkbenchPane = {\n id: 'shell',\n title: 'Shell',\n description: 'Commands the agent ran and their output',\n icon: TerminalIcon,\n render: () => <SessionShellPane />,\n};\n\nexport const SESSION_WORKBENCH_COMPUTER_PANE: SessionWorkbenchPane = {\n id: 'computer',\n title: 'Computer',\n description: 'The machine this session works on, and how to reach it',\n icon: MonitorIcon,\n render: () => <SessionComputerPane />,\n};\n\nexport const SESSION_WORKBENCH_PULL_REQUESTS_PANE: SessionWorkbenchPane = {\n id: 'pull-requests',\n title: 'Pull requests',\n description: 'Pull requests this session opened, with checks and reviews',\n icon: GitPullRequestIcon,\n render: () => <SessionPullRequestsPane />,\n};\n\nexport const SESSION_WORKBENCH_ATTACHMENTS_PANE: SessionWorkbenchPane = {\n id: 'attachments',\n title: 'Attachments',\n description: 'Files and assets this session created or edited',\n icon: PaperclipIcon,\n render: () => <SessionAttachmentsPane />,\n};\n\n/** The built-in panes, in \"+\" menu order. Spread it to add your own. */\nexport const DEFAULT_SESSION_WORKBENCH_PANES: readonly SessionWorkbenchPane[] = [\n SESSION_WORKBENCH_TASKS_PANE,\n SESSION_WORKBENCH_SHELL_PANE,\n SESSION_WORKBENCH_COMPUTER_PANE,\n SESSION_WORKBENCH_PULL_REQUESTS_PANE,\n SESSION_WORKBENCH_ATTACHMENTS_PANE,\n];\n\n/** The panes a thread opens with until the person changes its tabs. */\nexport const DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS: readonly string[] = [\n SESSION_WORKBENCH_TASKS_PANE.id,\n SESSION_WORKBENCH_SHELL_PANE.id,\n SESSION_WORKBENCH_COMPUTER_PANE.id,\n];\n"],"names":["jsxs","jsx","AlertCircleIcon","useAuiState","hasStatewireThreadExtras","useStatewireState","readDeepAgentStreamValues","useMemo","taskProgress","deriveTaskSteps","ListChecksIcon","PlanStepMarker","cn","LoaderIcon","CheckIcon","XIcon","CircleDashedIcon","relativeTime","useSessionWorkbench","useSessionWorkbenchWorkspace","useStatewireHistory","deriveShellRows","useState","filterShellRows","TerminalIcon","SearchIcon","useAthenaComputerStatus","computerStateBadge","useAthenaComputerSshAccess","_a","CopyIcon","useAthenaConfig","createAthenaSpacesUrl","athenaLinkAppUrl","ExternalLinkIcon","MonitorIcon","workspaceComputers","ComputerLiveDesktop","Fragment","pullRequestChipState","PR_STATE_ICON","PR_CHECKS_LABEL","reviewDecisionLabel","PR_STATE_CLASS","useAthenaStatewireThreadList","useAthenaSessionAttention","GitPullRequestIcon","orderedPullRequests","FileSpreadsheetIcon","FileTextIcon","PresentationIcon","BookOpenIcon","ImageIcon","FolderIcon","useAssetPanelStore","FileIcon","assetPanelTypeOf","assetTypeLabel","PaperclipIcon"],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { useStatewireState } from "@assistant-ui/react-statewire";
|
|
|
4
4
|
import { ListChecksIcon, TerminalIcon, MonitorIcon, GitPullRequestIcon, PaperclipIcon, AlertCircleIcon, FileTextIcon, FolderIcon, ImageIcon, BookOpenIcon, PresentationIcon, FileSpreadsheetIcon, FileIcon, ExternalLinkIcon, SearchIcon, CheckIcon, CopyIcon, LoaderIcon, XIcon, CircleDashedIcon } from "lucide-react";
|
|
5
5
|
import { useMemo, useState } from "react";
|
|
6
6
|
import { useAssetPanelStore } from "../assets/asset-panel-store.js";
|
|
7
|
-
import { createAthenaSpacesUrl } from "../lib/athena-urls.js";
|
|
7
|
+
import { createAthenaSpacesUrl, athenaLinkAppUrl } from "../lib/athena-urls.js";
|
|
8
8
|
import { useAthenaConfig } from "../provider/AthenaContext.js";
|
|
9
9
|
import { useStatewireHistory } from "../provider/statewire-history-context.js";
|
|
10
10
|
import { PR_CHECKS_LABEL, PR_STATE_ICON, PR_STATE_CLASS } from "../threads/pull-request-display.js";
|
|
@@ -13,7 +13,7 @@ import { useAthenaStatewireThreadList } from "../threads/statewire-thread-list.j
|
|
|
13
13
|
import { useAthenaSessionAttention } from "../threads/use-athena-session-attention.js";
|
|
14
14
|
import { PlanStepMarker } from "../tools/write-todos-tool-ui.js";
|
|
15
15
|
import { useSessionWorkbench, useSessionWorkbenchWorkspace } from "./session-workbench-context.js";
|
|
16
|
-
import { workspaceComputers, assetPanelTypeOf, assetTypeLabel, reviewDecisionLabel, deriveShellRows, filterShellRows, taskProgress, deriveTaskSteps, computerStateBadge
|
|
16
|
+
import { workspaceComputers, assetPanelTypeOf, assetTypeLabel, reviewDecisionLabel, deriveShellRows, filterShellRows, taskProgress, deriveTaskSteps, computerStateBadge } from "./session-workbench-model.js";
|
|
17
17
|
import { ComputerLiveDesktop } from "./ComputerLiveDesktop.js";
|
|
18
18
|
import { useAthenaComputerStatus, useAthenaComputerSshAccess } from "./use-session-workspace.js";
|
|
19
19
|
import { hasStatewireThreadExtras } from "../agent-runtime/src/thread-extras.js";
|