extracted chat component to widgets
This commit is contained in:
@@ -40,6 +40,7 @@ export function App() {
|
||||
<Route path="/settings/ai" element={<Dashboard.AISettings />} />
|
||||
<Route path="/settings/server" element={<Dashboard.ServerSettings />} />
|
||||
<Route path="/settings/resources" element={<Dashboard.ResourceSettings />} />
|
||||
<Route path="/chat" element={<Dashboard.SessionList />} />
|
||||
<Route path="/chat/new" element={<Dashboard.NewChat />} />
|
||||
<Route path="/chat/:sessionId" element={<Dashboard.ClaudeChat />} />
|
||||
<Route path="/chat/opencode/new" element={<Dashboard.OpenCodeChat />} />
|
||||
|
||||
+3
-6
@@ -1,13 +1,10 @@
|
||||
import { useRef, useEffect, useState } from 'react';
|
||||
import { useNavigate, useLocation } from 'react-router';
|
||||
import { useSessions } from './state/useSessions';
|
||||
import { useSessions, useOpenCodeSessions, useSlashCommands, SessionBar } from 'widgets/ChatHistory';
|
||||
import type { ModelOption } from '@/state/useModels';
|
||||
import { useOpenCodeSessions } from './state/useOpenCodeSessions';
|
||||
import type { useClaude, Attachment } from 'plugins/Chat/client';
|
||||
import { EmbeddableChat } from 'plugins/Chat/client';
|
||||
import { useSlashCommands } from './state/useSlashCommands';
|
||||
import type { useClaude } from './useClaude';
|
||||
import { EmbeddableChat, type Attachment } from './EmbeddableChat';
|
||||
import { Card } from '@/components/Card';
|
||||
import { SessionBar } from './SessionBar';
|
||||
|
||||
export type { Attachment };
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { toast } from 'sonner';
|
||||
import { useClient } from 'hooks/useClient';
|
||||
import type { ModelOption } from '@/state/useModels';
|
||||
import type { useClaude } from './useClaude';
|
||||
import { MessageList } from './MessageList';
|
||||
import { MessageList } from 'widgets/Chat';
|
||||
import { InputArea } from './InputArea';
|
||||
|
||||
export type Attachment =
|
||||
+1
-1
@@ -10,7 +10,7 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import type { ModelOption } from '@/state/useModels';
|
||||
import type { ChatMessage } from './types';
|
||||
import type { ChatMessage } from 'widgets/Chat';
|
||||
import type { Attachment } from './EmbeddableChat';
|
||||
import { Settings } from './Settings';
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { useAuth } from 'hooks/useAuth';
|
||||
import type { ModelOption } from '@/state/useModels';
|
||||
import type { ChatMessage } from './types';
|
||||
import type { ChatMessage } from 'widgets/Chat';
|
||||
import { OpenCodeModelPicker } from './OpenCodeModelPicker';
|
||||
|
||||
type SettingsProps = {
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useState } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useClaude, useOpenCode, type SessionEntry } from 'plugins/Chat/client';
|
||||
import { ChatPanel } from 'plugins/ChatHistory/client';
|
||||
import type { SessionEntry } from 'widgets/Chat';
|
||||
import { useClaude } from './useClaude';
|
||||
import { useOpenCode } from './useOpenCode';
|
||||
import { ChatPanel } from './ChatPanel';
|
||||
import { useVisibleClaudeModels, useVisibleOpenCodeModels } from '@/state/useModels';
|
||||
|
||||
export const ClaudeChat = () => {
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useChatWebSocket } from 'hooks/useChatWebSocket';
|
||||
import { useSessions } from 'plugins/ChatHistory/client';
|
||||
import type { ChatMessage, ServerMessage, TaskInfo } from './types';
|
||||
import { useSessions } from 'widgets/ChatHistory';
|
||||
import type { ChatMessage, ServerMessage, TaskInfo } from 'widgets/Chat';
|
||||
|
||||
const SAVE_DEBOUNCE_MS = 1000;
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@ import { useState, useEffect, useRef } from 'react';
|
||||
import { useChatWebSocket } from 'hooks/useChatWebSocket';
|
||||
import { useSettings } from '@/state/useSettings';
|
||||
import { useVisibleOpenCodeModels } from '@/state/useModels';
|
||||
import { useOpenCodeSessions } from 'plugins/ChatHistory/client';
|
||||
import type { ChatMessage, ServerMessage, TaskInfo } from './types';
|
||||
import { useOpenCodeSessions } from 'widgets/ChatHistory';
|
||||
import type { ChatMessage, ServerMessage, TaskInfo } from 'widgets/Chat';
|
||||
|
||||
type UseOpenCodeOptions = {
|
||||
replaceUrl?: boolean;
|
||||
+1
-2
@@ -3,8 +3,7 @@ import { Link } from 'react-router';
|
||||
import { Plus, MessageSquare, Trash2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card } from '@/components/Card';
|
||||
import { useSessions } from './state/useSessions';
|
||||
import { useOpenCodeSessions } from './state/useOpenCodeSessions';
|
||||
import { useSessions, useOpenCodeSessions } from 'widgets/ChatHistory';
|
||||
|
||||
type Filter = 'all' | 'claude' | 'opencode';
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@ import { useMemo } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { MessageSquare, Trash2, ChevronDown, ChevronUp } from 'lucide-react';
|
||||
import { Card } from '@/components/Card';
|
||||
import { useSessions } from './state/useSessions';
|
||||
import { useOpenCodeSessions } from './state/useOpenCodeSessions';
|
||||
import { useSessions } from 'widgets/ChatHistory';
|
||||
import { useOpenCodeSessions } from 'widgets/ChatHistory';
|
||||
import { useUserState } from '@/state/useUserState';
|
||||
|
||||
export const ChatHistory = () => {
|
||||
@@ -0,0 +1,2 @@
|
||||
export { ChatHistory as ChatHistoryWidget } from './Widget';
|
||||
export { SessionList } from './Screen';
|
||||
@@ -3,7 +3,10 @@ import { X } from 'lucide-react';
|
||||
import { Dialog, DialogOverlay, DialogPortal } from '@/components/ui/dialog';
|
||||
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||
import { cardStyle } from '@/components/Card';
|
||||
import { useClaude, useOpenCode, EmbeddableChat, type TaskInfo } from 'plugins/Chat/client';
|
||||
import type { TaskInfo } from 'widgets/Chat';
|
||||
import { useClaude } from '@/Screens/Dashboard/Chat/useClaude';
|
||||
import { useOpenCode } from '@/Screens/Dashboard/Chat/useOpenCode';
|
||||
import { EmbeddableChat } from '@/Screens/Dashboard/Chat/EmbeddableChat';
|
||||
import { useVisibleClaudeModels, useVisibleOpenCodeModels } from '@/state/useModels';
|
||||
import { useSettings } from '@/state/useSettings';
|
||||
import type { TaskSummary } from 'widgets/FileBrowser';
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { useSettings } from '@/state/useSettings';
|
||||
import { useVisibleClaudeModels, useVisibleOpenCodeModels } from '@/state/useModels';
|
||||
import type { Attachment } from 'plugins/Chat/client';
|
||||
import type { Attachment } from '@/Screens/Dashboard/Chat/EmbeddableChat';
|
||||
|
||||
export const ChatLauncher = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ChatLauncher } from './ChatLauncher';
|
||||
import { FileBrowserWidget as FileBrowser } from '@/Screens/Dashboard/Files';
|
||||
import { Widget as ChatHistory } from 'plugins/ChatHistory/client';
|
||||
import { ChatHistoryWidget as ChatHistory } from '@/Screens/Dashboard/ChatHistory';
|
||||
import { Catalog } from 'sounds';
|
||||
|
||||
export const HomeScreen = () => {
|
||||
|
||||
@@ -10,7 +10,9 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } f
|
||||
import { useClient } from 'hooks/useClient';
|
||||
import { useVisibleClaudeModels } from '@/state/useModels';
|
||||
import { Card } from '@/components/Card';
|
||||
import { useClaude, EmbeddableChat, type ChatMessage } from 'plugins/Chat/client';
|
||||
import type { ChatMessage } from 'widgets/Chat';
|
||||
import { useClaude } from '@/Screens/Dashboard/Chat/useClaude';
|
||||
import { EmbeddableChat } from '@/Screens/Dashboard/Chat/EmbeddableChat';
|
||||
type ResourceSummary = {
|
||||
dirName: string;
|
||||
name: string;
|
||||
|
||||
@@ -5,7 +5,9 @@ import { toast } from 'sonner';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card } from '@/components/Card';
|
||||
import { useClient } from 'hooks/useClient';
|
||||
import { EmbeddableChat, useClaude, useOpenCode } from 'plugins/Chat/client';
|
||||
import { useClaude } from '@/Screens/Dashboard/Chat/useClaude';
|
||||
import { useOpenCode } from '@/Screens/Dashboard/Chat/useOpenCode';
|
||||
import { EmbeddableChat } from '@/Screens/Dashboard/Chat/EmbeddableChat';
|
||||
import { useVisibleClaudeModels, useVisibleOpenCodeModels } from '@/state/useModels';
|
||||
|
||||
type AppStatus = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
||||
import { Search, AlertCircle, CheckCircle2, Clock, ArrowLeft } from 'lucide-react';
|
||||
import { useClient } from 'hooks/useClient';
|
||||
import { Card } from '@/components/Card';
|
||||
import { MessageBubble, type ChatMessage } from 'plugins/Chat/client';
|
||||
import { MessageBubble, type ChatMessage } from 'widgets/Chat';
|
||||
|
||||
type LogMetadata = {
|
||||
filename: string;
|
||||
|
||||
@@ -12,3 +12,4 @@ export * from './TaskLogs';
|
||||
export * from './Tasks';
|
||||
export * from './Terminal';
|
||||
export * from './Files';
|
||||
export * from './ChatHistory';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useSessions } from 'plugins/ChatHistory/client';
|
||||
import { useSessions } from 'widgets/ChatHistory';
|
||||
import { usePlans } from './usePlans';
|
||||
import { useSettings } from './useSettings';
|
||||
import { useThemeSync } from './useThemeSync';
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
export * from './client';
|
||||
|
||||
export const plugin = {
|
||||
id: 'Chat',
|
||||
name: 'Chat',
|
||||
description: 'Embeddable chat UI',
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
export { ChatHistory as Widget } from './Widget';
|
||||
export { SessionList as Screen } from './Screen';
|
||||
export { ChatPanel } from './ChatPanel';
|
||||
export { SessionBar } from './SessionBar';
|
||||
export { useSessions } from './state/useSessions';
|
||||
export { useOpenCodeSessions } from './state/useOpenCodeSessions';
|
||||
export { useSlashCommands, type SlashCommandResult } from './state/useSlashCommands';
|
||||
@@ -1,7 +0,0 @@
|
||||
export { Widget, Screen, ChatPanel, SessionBar } from './client';
|
||||
|
||||
export const plugin = {
|
||||
id: 'ChatHistory',
|
||||
name: 'Chat History',
|
||||
description: 'Session management for chat history',
|
||||
};
|
||||
@@ -1,259 +0,0 @@
|
||||
# Building a Plugin
|
||||
|
||||
Plugins are self-contained modules that extend Officer with new features. They live under `src/workspaces/plugins/` and are auto-discovered at startup — no registration step required.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
src/workspaces/plugins/
|
||||
├── package.json # Workspace exports (update when adding a plugin)
|
||||
└── MyPlugin/
|
||||
├── index.ts # Metadata + re-exports
|
||||
├── server/
|
||||
│ ├── index.ts # Exports router and apiPath
|
||||
│ └── router.ts # Hono API routes
|
||||
└── client/
|
||||
├── index.ts # Exports Widget and/or Screen
|
||||
├── Widget.tsx # Compact component (dashboard home)
|
||||
├── Screen/
|
||||
│ └── index.tsx # Full-page component (dedicated route)
|
||||
└── state/
|
||||
└── useMyPlugin.ts # API client hook
|
||||
```
|
||||
|
||||
A plugin can be server-only, client-only, or both. The discovery system checks for the presence of `server/index.ts` and `client/index.ts` to determine what the plugin provides.
|
||||
|
||||
## Step-by-Step
|
||||
|
||||
### 1. Create the plugin directory
|
||||
|
||||
```
|
||||
mkdir -p src/workspaces/plugins/MyPlugin/{server,client/state,client/Screen}
|
||||
```
|
||||
|
||||
### 2. Plugin metadata — `MyPlugin/index.ts`
|
||||
|
||||
Every plugin must export a `plugin` object with metadata. This is read by the settings UI and the `/plugins` API.
|
||||
|
||||
```ts
|
||||
export { Widget, Screen } from './client';
|
||||
export { router, apiPath } from './server';
|
||||
|
||||
export const plugin = {
|
||||
id: 'MyPlugin', // Must match directory name
|
||||
name: 'My Plugin', // Display name in settings
|
||||
description: 'What this plugin does',
|
||||
};
|
||||
```
|
||||
|
||||
If your plugin is server-only, omit the client export. If client-only, omit the server export.
|
||||
|
||||
### 3. Server router — `MyPlugin/server/`
|
||||
|
||||
**`server/index.ts`** — Exports the router instance and the API path prefix:
|
||||
|
||||
```ts
|
||||
export * from './router';
|
||||
|
||||
export const apiPath = 'my-plugin';
|
||||
```
|
||||
|
||||
The `apiPath` determines the URL prefix. This router gets mounted at `/api/my-plugin`.
|
||||
|
||||
**`server/router.ts`** — Define your API endpoints:
|
||||
|
||||
```ts
|
||||
import { createRouter } from '@@/create-router';
|
||||
import * as errors from '@@/custom-errors';
|
||||
|
||||
export const router = createRouter();
|
||||
|
||||
router.get('/items', async (ctx) => {
|
||||
const user = ctx.get('user'); // Authenticated user
|
||||
// ...
|
||||
return ctx.json({ items: [] });
|
||||
});
|
||||
|
||||
router.post('/items', async (ctx) => {
|
||||
const body = ctx.get('body'); // Parsed request body
|
||||
if (!body.name) throw errors.BAD_REQUEST('Name is required');
|
||||
// ...
|
||||
return ctx.json({ created: true });
|
||||
});
|
||||
```
|
||||
|
||||
Key points:
|
||||
- `createRouter()` from `@@/create-router` gives you a typed Hono router
|
||||
- All plugin routes are **protected** — user authentication is enforced automatically
|
||||
- Access the authenticated user with `ctx.get('user')` (returns `User` from types)
|
||||
- Access parsed body with `ctx.get('body')`
|
||||
- Throw `CustomError` instances for error responses — they're caught by the global error handler
|
||||
|
||||
**Available error helpers** (`@@/custom-errors`):
|
||||
- `BAD_REQUEST(msg?)` — 400
|
||||
- `UNAUTHORIZED(msg?)` — 401
|
||||
- `FORBIDDEN(msg?)` — 403
|
||||
- `NOT_FOUND(msg?)` — 404
|
||||
- `CONFLICT(msg?)` — 409
|
||||
- `INTERNAL_SERVER_ERROR(msg?)` — 500
|
||||
- `TOO_MANY_REQUESTS(msg?, retryAfter?)` — 429
|
||||
|
||||
**User data helpers** (`@@/data-path`):
|
||||
- `DATA_PATH` — base data directory
|
||||
- `getHomeDir(email)` — user's home directory
|
||||
|
||||
### 4. Client components — `MyPlugin/client/`
|
||||
|
||||
**`client/index.ts`** — Export your components with standardized names:
|
||||
|
||||
```ts
|
||||
export { MyPluginWidget as Widget } from './Widget';
|
||||
export { MyPluginScreen as Screen } from './Screen';
|
||||
```
|
||||
|
||||
**`client/state/useMyPlugin.ts`** — API client hook:
|
||||
|
||||
```ts
|
||||
import { useClient } from 'hooks/useClient';
|
||||
|
||||
type Item = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const useMyPlugin = () => {
|
||||
const client = useClient();
|
||||
|
||||
return {
|
||||
listItems: () => client.get<Item[]>('/my-plugin/items'),
|
||||
createItem: (name: string) => client.post('/my-plugin/items', { name }),
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
The `useClient()` hook provides an authenticated HTTP client. The path must match your `apiPath` from the server.
|
||||
|
||||
**`client/Widget.tsx`** — Compact component for the dashboard home:
|
||||
|
||||
```tsx
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useMyPlugin } from './state/useMyPlugin';
|
||||
|
||||
export const MyPluginWidget = () => {
|
||||
// Widget implementation
|
||||
};
|
||||
```
|
||||
|
||||
**`client/Screen/index.tsx`** — Full-page component:
|
||||
|
||||
```tsx
|
||||
import { DashboardLayout } from '@/Screens/Dashboard/Layout';
|
||||
|
||||
export const MyPluginScreen = () => {
|
||||
return (
|
||||
<DashboardLayout>
|
||||
{/* Screen implementation */}
|
||||
</DashboardLayout>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### 5. Register workspace exports — `plugins/package.json`
|
||||
|
||||
Add subpath exports so the monorepo can import your plugin:
|
||||
|
||||
```json
|
||||
{
|
||||
"exports": {
|
||||
"./FileBrowser": "./FileBrowser/index.ts",
|
||||
"./FileBrowser/client": "./FileBrowser/client/index.ts",
|
||||
"./FileBrowser/server": "./FileBrowser/server/index.ts",
|
||||
"./MyPlugin": "./MyPlugin/index.ts",
|
||||
"./MyPlugin/client": "./MyPlugin/client/index.ts",
|
||||
"./MyPlugin/server": "./MyPlugin/server/index.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This lets other code import your plugin as:
|
||||
|
||||
```ts
|
||||
import { Widget, Screen } from 'plugins/MyPlugin/client';
|
||||
import { router, apiPath } from 'plugins/MyPlugin/server';
|
||||
import { plugin } from 'plugins/MyPlugin';
|
||||
```
|
||||
|
||||
### 6. Wire into the app (optional)
|
||||
|
||||
The server router is auto-discovered and mounted — no changes needed. But if your plugin has client components that should appear in the main app, you'll need to add them manually:
|
||||
|
||||
**Route** — `src/apps/officer-web/App.tsx`:
|
||||
|
||||
```tsx
|
||||
import { Screen as MyPluginScreen } from 'plugins/MyPlugin/client';
|
||||
|
||||
// Inside the authenticated routes:
|
||||
{plugins?.MyPlugin !== false && <Route path="/my-plugin" element={<MyPluginScreen />} />}
|
||||
```
|
||||
|
||||
**Nav item** — `src/apps/officer-web/Screens/Dashboard/Layout.tsx`:
|
||||
|
||||
```tsx
|
||||
{plugins?.MyPlugin !== false && (
|
||||
<DropdownMenuItem asChild className="cursor-pointer">
|
||||
<Link to="/my-plugin">
|
||||
<SomeIcon className="mr-2 h-4 w-4" />
|
||||
My Plugin
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
```
|
||||
|
||||
**Home widget** — `src/apps/officer-web/Screens/Dashboard/Home/index.tsx`:
|
||||
|
||||
```tsx
|
||||
import { Widget as MyPluginWidget } from 'plugins/MyPlugin/client';
|
||||
|
||||
// Inside the layout:
|
||||
{plugins?.MyPlugin !== false && <MyPluginWidget />}
|
||||
```
|
||||
|
||||
The `plugins` object comes from `useServerSettings()` and is `undefined` when no overrides exist — so `plugins?.MyPlugin !== false` defaults to showing the plugin (opt-out model).
|
||||
|
||||
## Enable/Disable
|
||||
|
||||
Plugins are **enabled by default**. Admins can disable them in Server Settings > Plugins, which writes to `~/.config/officer.dev/server-settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"MyPlugin": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When disabled:
|
||||
- **Server-side**: The plugin router is not mounted (requires server restart)
|
||||
- **Client-side**: Routes, nav items, and widgets are hidden immediately
|
||||
|
||||
## Import Aliases
|
||||
|
||||
| Alias | Resolves to | Use in |
|
||||
|-------|-------------|--------|
|
||||
| `@@/` | `src/servers/` | Server code (`createRouter`, `custom-errors`, `data-path`) |
|
||||
| `@/` | `src/apps/officer-web/` | Client code (`components/ui/*`, `Screens/*`, `state/*`) |
|
||||
| `hooks/` | `src/workspaces/hooks/src/` | Both (`useClient`, `useAuth`) |
|
||||
| `types` | `src/workspaces/types/` | Both |
|
||||
| `config` | `src/workspaces/config/` | Client code |
|
||||
| `plugins/` | `src/workspaces/plugins/` | Both |
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] `MyPlugin/index.ts` exports `plugin` metadata with `id` matching directory name
|
||||
- [ ] `MyPlugin/server/index.ts` exports `router` and `apiPath`
|
||||
- [ ] `MyPlugin/client/index.ts` exports `Widget` and/or `Screen`
|
||||
- [ ] `plugins/package.json` has subpath exports for the new plugin
|
||||
- [ ] App routes gated with `plugins?.MyPlugin !== false`
|
||||
- [ ] Nav items gated with `plugins?.MyPlugin !== false`
|
||||
- [ ] Home widgets gated with `plugins?.MyPlugin !== false`
|
||||
- [ ] `bunx tsgo` — no new type errors
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "plugins",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./Chat": "./Chat/index.ts",
|
||||
"./Chat/client": "./Chat/client/index.ts",
|
||||
"./ChatHistory": "./ChatHistory/index.ts",
|
||||
"./ChatHistory/client": "./ChatHistory/client/index.ts"
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,5 @@
|
||||
export { EmbeddableChat, type Attachment } from './EmbeddableChat';
|
||||
export { MessageList } from './MessageList';
|
||||
export { InputArea } from './InputArea';
|
||||
export { Settings } from './Settings';
|
||||
export { MessageBubble, StreamingBubble } from './MessageBubble';
|
||||
export { ToolActivity } from './ToolActivity';
|
||||
export { QuestionActivity } from './QuestionActivity';
|
||||
export { OpenCodeModelPicker } from './OpenCodeModelPicker';
|
||||
export { useClaude } from './useClaude';
|
||||
export { useOpenCode } from './useOpenCode';
|
||||
export type { ChatMessage, SessionEntry, ServerMessage, TaskInfo } from './types';
|
||||
@@ -0,0 +1,4 @@
|
||||
export { SessionBar } from './SessionBar';
|
||||
export { useSessions } from './useSessions';
|
||||
export { useOpenCodeSessions } from './useOpenCodeSessions';
|
||||
export { useSlashCommands, type SlashCommandResult } from './useSlashCommands';
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import type { SessionEntry, ChatMessage } from 'plugins/Chat/client';
|
||||
import type { SessionEntry, ChatMessage } from 'widgets/Chat';
|
||||
import { useAuth } from 'hooks/useAuth';
|
||||
import { useClient } from 'hooks/useClient';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import type { SessionEntry, ChatMessage } from 'plugins/Chat/client';
|
||||
import type { SessionEntry, ChatMessage } from 'widgets/Chat';
|
||||
import type { SlashCommandResult } from './useSlashCommands';
|
||||
import { useAuth } from 'hooks/useAuth';
|
||||
import { useClient } from 'hooks/useClient';
|
||||
@@ -3,6 +3,8 @@
|
||||
"private": true,
|
||||
"exports": {
|
||||
"./Terminal": "./Terminal/index.ts",
|
||||
"./FileBrowser": "./FileBrowser/index.ts"
|
||||
"./FileBrowser": "./FileBrowser/index.ts",
|
||||
"./ChatHistory": "./ChatHistory/index.ts",
|
||||
"./Chat": "./Chat/index.ts"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user