Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
commit
03634b1ca3
11340 files changed
+3442369
No files matched your search
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* Wiring surfaces — each pane is its own memoized component. Every surface
|
||||
* reads the reactive state it renders from at the leaf (its own atom
|
||||
* subscriptions) and reaches the controller's callbacks through the stable
|
||||
* `actions` bag, so a state change scoped to one surface (or a bare
|
||||
* wiring-controller tick) never re-renders another. This is what keeps the
|
||||
* layout tree's zones independently rendered — the whole point of the shell.
|
||||
*/
|
||||
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { type ComponentProps, lazy, memo, type ReactNode, Suspense, useMemo } from 'react'
|
||||
import { Navigate, Route, Routes, useParams } from 'react-router'
|
||||
|
||||
import { ContribBoundary, ContribRender } from '@/contrib/react/boundary'
|
||||
import { useContributions } from '@/contrib/react/use-contributions'
|
||||
import { $activeConnectionId } from '@/store/connections'
|
||||
import { $gateway } from '@/store/gateway'
|
||||
import { $activeGatewayProfile } from '@/store/profile'
|
||||
import { $freshDraftReady, $gatewayState } from '@/store/session'
|
||||
|
||||
import { ChatView } from '../chat'
|
||||
import { ChatSidebar } from '../chat/sidebar'
|
||||
import { TerminalPaneChrome } from '../right-sidebar/terminal/chrome'
|
||||
import { contributedRoutes, NEW_CHAT_ROUTE, ROUTES_AREA, sessionRoute } from '../routes'
|
||||
import { useStatusSnapshot } from '../shell/hooks/use-status-snapshot'
|
||||
import { useStatusbarItems } from '../shell/hooks/use-statusbar-items'
|
||||
import { ModelMenuPanel } from '../shell/model-menu-panel'
|
||||
import { StatusbarControls } from '../shell/statusbar-controls'
|
||||
|
||||
import { latestChatActions, latestSidebarActions } from './latest-actions'
|
||||
import { setStatusbarItemGroup, useStatusbarContributions } from './panes'
|
||||
import type { SidebarActions, WiringActions } from './types'
|
||||
|
||||
// Same lazy-view split as DesktopController — pages load on demand. The
|
||||
// full-page views the workspace route table mounts live here; overlay views
|
||||
// (agents/settings/…) are the controller's and stay in wiring.tsx.
|
||||
const ArtifactsView = lazy(async () => ({ default: (await import('../artifacts')).ArtifactsView }))
|
||||
const MessagingView = lazy(async () => ({ default: (await import('../messaging')).MessagingView }))
|
||||
const SkillsView = lazy(async () => ({ default: (await import('../skills')).SkillsView }))
|
||||
|
||||
export function LegacySessionRedirect() {
|
||||
const { sessionId } = useParams()
|
||||
|
||||
return <Navigate replace to={sessionId ? sessionRoute(sessionId) : NEW_CHAT_ROUTE} />
|
||||
}
|
||||
|
||||
export const SidebarSurface = memo(function SidebarSurface({
|
||||
actions,
|
||||
currentView
|
||||
}: {
|
||||
actions: SidebarActions
|
||||
currentView: ComponentProps<typeof ChatSidebar>['currentView']
|
||||
}) {
|
||||
const latestActions = useMemo(() => latestSidebarActions(actions), [actions])
|
||||
|
||||
return <ChatSidebar currentView={currentView} {...latestActions} />
|
||||
})
|
||||
|
||||
export const TerminalSurface = memo(function TerminalSurface() {
|
||||
return (
|
||||
<div className="relative flex h-full min-h-0 flex-col overflow-hidden bg-(--ui-terminal-surface-background)">
|
||||
<TerminalPaneChrome />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
/** Owns the statusbar's own data hooks (status snapshot poll, contributed
|
||||
* items) so its 15s refresh — and any statusbar-only churn — re-renders the
|
||||
* bar alone, never the chat/sidebar/terminal. */
|
||||
export const StatusbarSurface = memo(function StatusbarSurface({
|
||||
actions,
|
||||
agentsOpen,
|
||||
chatOpen,
|
||||
commandCenterOpen
|
||||
}: {
|
||||
actions: WiringActions
|
||||
agentsOpen: boolean
|
||||
chatOpen: boolean
|
||||
commandCenterOpen: boolean
|
||||
}) {
|
||||
const activeConnectionId = useStore($activeConnectionId)
|
||||
const activeGatewayProfile = useStore($activeGatewayProfile)
|
||||
const gatewayState = useStore($gatewayState)
|
||||
const freshDraftReady = useStore($freshDraftReady)
|
||||
const gatewayScope = `${activeConnectionId ?? ''}\0${activeGatewayProfile}`
|
||||
const { inferenceStatus, statusSnapshot } = useStatusSnapshot(gatewayState, actions.requestGateway, gatewayScope)
|
||||
const extraLeftItems = useStatusbarContributions('left')
|
||||
const extraRightItems = useStatusbarContributions('right')
|
||||
|
||||
const { leftStatusbarItems, statusbarItems } = useStatusbarItems({
|
||||
agentsOpen,
|
||||
chatOpen,
|
||||
commandCenterOpen,
|
||||
extraLeftItems,
|
||||
extraRightItems,
|
||||
freshDraftReady,
|
||||
gatewayState,
|
||||
inferenceStatus,
|
||||
openAgents: actions.openAgents,
|
||||
openCommandCenterSection: actions.openCommandCenterSection,
|
||||
requestGateway: actions.requestGateway,
|
||||
statusSnapshot,
|
||||
toggleCommandCenter: actions.toggleCommandCenter
|
||||
})
|
||||
|
||||
return <StatusbarControls items={statusbarItems} leftItems={leftStatusbarItems} />
|
||||
})
|
||||
|
||||
/** The workspace pane: the real route table (chat + full-page views + plugin
|
||||
* routes). Subscribes to the gateway instance/state and ROUTES_AREA itself;
|
||||
* the voice cap arrives as a prop. ChatView subscribes to its own session
|
||||
* atoms, so streaming never round-trips through the controller. */
|
||||
export const ChatRoutesSurface = memo(function ChatRoutesSurface({
|
||||
actions,
|
||||
maxVoiceRecordingSeconds
|
||||
}: {
|
||||
actions: WiringActions
|
||||
maxVoiceRecordingSeconds?: number
|
||||
}) {
|
||||
const activeConnectionId = useStore($activeConnectionId)
|
||||
const activeGatewayProfile = useStore($activeGatewayProfile)
|
||||
const gateway = useStore($gateway)
|
||||
const gatewayState = useStore($gatewayState)
|
||||
useContributions(ROUTES_AREA)
|
||||
const routeContributions = contributedRoutes()
|
||||
|
||||
const modelMenuContent = useMemo(
|
||||
() =>
|
||||
gatewayState === 'open' ? (
|
||||
<ModelMenuPanel
|
||||
gateway={gateway || undefined}
|
||||
onSelectModel={actions.selectModel}
|
||||
ownerConnectionId={activeConnectionId || undefined}
|
||||
profile={activeGatewayProfile}
|
||||
requestGateway={actions.requestGateway}
|
||||
/>
|
||||
) : null,
|
||||
[actions, activeConnectionId, activeGatewayProfile, gateway, gatewayState]
|
||||
)
|
||||
|
||||
const chatActions = useMemo(() => latestChatActions(actions), [actions])
|
||||
|
||||
const chatView = (
|
||||
<ChatView
|
||||
gateway={gateway}
|
||||
maxVoiceRecordingSeconds={maxVoiceRecordingSeconds}
|
||||
modelMenuContent={modelMenuContent}
|
||||
modelOptionsOwnerConnectionId={activeConnectionId || undefined}
|
||||
modelOptionsProfile={activeGatewayProfile}
|
||||
requestModelOptionsForOwner={actions.requestGateway}
|
||||
{...chatActions}
|
||||
/>
|
||||
)
|
||||
|
||||
// FULL-PAGE views (not chat): a page is not a tab-able surface, so the zone's
|
||||
// tab strip stands down while one is showing. That is `paneChrome.headerVeto`
|
||||
// on the contribution, not a DOM marker — the `data-zone-no-header` attribute
|
||||
// that used to ride this wrapper gated a body double-click toggle that no
|
||||
// longer exists, and nothing has read it since.
|
||||
const page = (view: ReactNode) => (
|
||||
<div className="contents">
|
||||
<Suspense fallback={null}>{view}</Suspense>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Route element={chatView} index />
|
||||
<Route element={chatView} path=":sessionId" />
|
||||
<Route element={page(<SkillsView setStatusbarItemGroup={setStatusbarItemGroup} />)} path="skills" />
|
||||
<Route element={page(<MessagingView setStatusbarItemGroup={setStatusbarItemGroup} />)} path="messaging" />
|
||||
<Route element={page(<ArtifactsView setStatusbarItemGroup={setStatusbarItemGroup} />)} path="artifacts" />
|
||||
<Route element={null} path="agents" />
|
||||
<Route element={null} path="command-center" />
|
||||
<Route element={null} path="cron" />
|
||||
<Route element={null} path="profiles" />
|
||||
<Route element={null} path="settings" />
|
||||
<Route element={null} path="starmap" />
|
||||
<Route element={null} path="webhooks" />
|
||||
{/* Registry-contributed pages (core features + plugins) render in the
|
||||
workspace pane like any built-in view — behind the same blast wall
|
||||
as every other contribution mount. */}
|
||||
{routeContributions.map(route => (
|
||||
<Route
|
||||
element={page(
|
||||
<ContribBoundary id={route.key}>
|
||||
<ContribRender render={route.render} />
|
||||
</ContribBoundary>
|
||||
)}
|
||||
key={route.key}
|
||||
path={route.path.slice(1)}
|
||||
/>
|
||||
))}
|
||||
<Route element={<Navigate replace to={NEW_CHAT_ROUTE} />} path="new" />
|
||||
<Route element={<LegacySessionRedirect />} path="sessions/:sessionId" />
|
||||
<Route element={<Navigate replace to={NEW_CHAT_ROUTE} />} path="*" />
|
||||
</Routes>
|
||||
)
|
||||
})
|
||||
Reference in new issue
Block a user