218 lines
8.3 KiB
Markdown
218 lines
8.3 KiB
Markdown
---
|
|
phase: 33-persistent-memory
|
|
plan: 02
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- ui/src/pages/PersonalAssistant.tsx
|
|
- ui/src/api/assistantMemory.ts
|
|
- ui/src/hooks/useNexusMode.ts
|
|
- ui/src/App.tsx
|
|
- ui/src/components/Layout.tsx
|
|
autonomous: true
|
|
requirements: [ASST-04]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "PersonalAssistantPage is visible when mode is personal_ai or both"
|
|
- "PersonalAssistantPage is hidden (route redirects) when mode is project_builder"
|
|
- "User can navigate to assistant page from sidebar"
|
|
- "Assistant page renders the existing ChatPanel component for chat functionality"
|
|
artifacts:
|
|
- path: "ui/src/pages/PersonalAssistant.tsx"
|
|
provides: "Personal assistant page component"
|
|
exports: ["PersonalAssistant"]
|
|
- path: "ui/src/hooks/useNexusMode.ts"
|
|
provides: "React Query hook for nexus settings mode"
|
|
exports: ["useNexusMode"]
|
|
- path: "ui/src/api/assistantMemory.ts"
|
|
provides: "API client for memory endpoints"
|
|
exports: ["assistantMemoryApi"]
|
|
key_links:
|
|
- from: "ui/src/pages/PersonalAssistant.tsx"
|
|
to: "ui/src/hooks/useNexusMode.ts"
|
|
via: "useNexusMode hook"
|
|
pattern: "useNexusMode"
|
|
- from: "ui/src/App.tsx"
|
|
to: "ui/src/pages/PersonalAssistant.tsx"
|
|
via: "Route element"
|
|
pattern: "PersonalAssistant"
|
|
- from: "ui/src/components/Layout.tsx"
|
|
to: "assistant route"
|
|
via: "NavLink in sidebar"
|
|
pattern: "assistant"
|
|
---
|
|
|
|
<objective>
|
|
Create the Personal Assistant page, mode-gating hook, and memory API client. Wire the route and sidebar navigation.
|
|
|
|
Purpose: ASST-04 requires assistant and project builder modes to work standalone or together. The PersonalAssistantPage is the entry point for assistant mode.
|
|
Output: Working assistant page with mode-gated visibility, sidebar link, and memory API client.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
|
@$HOME/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/33-persistent-memory/33-RESEARCH.md
|
|
@ui/src/App.tsx
|
|
@ui/src/components/Layout.tsx
|
|
@ui/src/api/hardware.ts
|
|
@ui/src/components/ChatPanel.tsx
|
|
</context>
|
|
|
|
<interfaces>
|
|
<!-- Existing code the executor needs -->
|
|
|
|
From ui/src/api/hardware.ts:
|
|
```typescript
|
|
export type NexusMode = "personal_ai" | "project_builder" | "both";
|
|
export interface NexusSettings { mode: NexusMode; }
|
|
export function fetchNexusSettings(): Promise<NexusSettings>;
|
|
```
|
|
|
|
From ui/src/App.tsx (route pattern):
|
|
```typescript
|
|
// Board routes at line 122-180
|
|
function boardRoutes() {
|
|
return <>
|
|
<Route index element={<Navigate to="dashboard" replace />} />
|
|
<Route path="dashboard" element={<Dashboard />} />
|
|
// ... more routes
|
|
</>;
|
|
}
|
|
```
|
|
|
|
From ui/src/components/Layout.tsx (sidebar pattern):
|
|
```typescript
|
|
// ChatPanel rendered at line 463
|
|
// Sidebar NavLinks with icons (lucide-react)
|
|
```
|
|
|
|
From ui/src/components/ChatPanel.tsx:
|
|
```typescript
|
|
// Existing chat panel component — renders conversation list + message list
|
|
// Used as slide-over panel in Layout
|
|
```
|
|
</interfaces>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create useNexusMode hook, memory API client, and PersonalAssistantPage</name>
|
|
<files>
|
|
ui/src/hooks/useNexusMode.ts,
|
|
ui/src/api/assistantMemory.ts,
|
|
ui/src/pages/PersonalAssistant.tsx
|
|
</files>
|
|
<action>
|
|
Create `ui/src/hooks/useNexusMode.ts`:
|
|
- Export `useNexusMode()` hook that calls `useQuery` with key `["nexus", "settings"]` fetching `fetchNexusSettings()` from `../api/hardware`
|
|
- Return `{ mode, isLoading, isAssistantEnabled }` where `isAssistantEnabled = mode !== "project_builder"`
|
|
- Default mode to `"both"` while loading
|
|
|
|
Create `ui/src/api/assistantMemory.ts`:
|
|
- Export `assistantMemoryApi` object with:
|
|
- `getMemory(companyId: string)` — GET `/assistant-memory/${companyId}` using `api.get`
|
|
- `appendFact(companyId: string, fact: string)` — PATCH `/assistant-memory/${companyId}` with `{ fact }`
|
|
- `clearMemory(companyId: string)` — DELETE `/assistant-memory/${companyId}`
|
|
- Import `api` from `./client`
|
|
|
|
Create `ui/src/pages/PersonalAssistant.tsx`:
|
|
- Export default `PersonalAssistant` component
|
|
- Use `useNexusMode()` — if `!isAssistantEnabled`, render `<Navigate to="/dashboard" replace />`
|
|
- Render a full-page chat layout:
|
|
- Use `useCompany()` to get `selectedCompany`
|
|
- Create or retrieve an assistant conversation (use existing `chatApi.listConversations` with a dedicated agent filter, or create a new one)
|
|
- Render `ChatPanel`-style UI: conversation list on left, messages on right
|
|
- Include a header with "Personal Assistant" title and a "Turn this into a project" button (wired in Plan 03)
|
|
- Styling: Use existing Tailwind patterns from Layout.tsx. Full height (`h-full`), flex layout, clean assistant-focused design.
|
|
- The "Turn this into a project" button should be present but disabled with tooltip "Coming soon" — Plan 03 wires the actual handoff.
|
|
</action>
|
|
<read_first>
|
|
ui/src/api/hardware.ts,
|
|
ui/src/api/client.ts,
|
|
ui/src/components/ChatPanel.tsx,
|
|
ui/src/context/CompanyContext.tsx,
|
|
ui/src/hooks/useStreamingChat.ts,
|
|
ui/src/components/ChatMessageList.tsx
|
|
</read_first>
|
|
<verify>
|
|
<automated>pnpm --filter @paperclipai/ui tsc --noEmit</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- grep -q "useNexusMode" ui/src/hooks/useNexusMode.ts
|
|
- grep -q "isAssistantEnabled" ui/src/hooks/useNexusMode.ts
|
|
- grep -q "fetchNexusSettings" ui/src/hooks/useNexusMode.ts
|
|
- grep -q "assistantMemoryApi" ui/src/api/assistantMemory.ts
|
|
- grep -q "appendFact" ui/src/api/assistantMemory.ts
|
|
- grep -q "PersonalAssistant" ui/src/pages/PersonalAssistant.tsx
|
|
- grep -q "useNexusMode" ui/src/pages/PersonalAssistant.tsx
|
|
- grep -q "project_builder\|isAssistantEnabled" ui/src/pages/PersonalAssistant.tsx
|
|
</acceptance_criteria>
|
|
<done>
|
|
PersonalAssistant page renders full-page chat when mode allows, redirects to dashboard when project_builder only. Memory API client ready. Mode hook available for any component.
|
|
</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Wire assistant route in App.tsx and sidebar link in Layout.tsx</name>
|
|
<files>
|
|
ui/src/App.tsx,
|
|
ui/src/components/Layout.tsx
|
|
</files>
|
|
<action>
|
|
In `ui/src/App.tsx`:
|
|
- Add lazy import: `const PersonalAssistant = React.lazy(() => import("./pages/PersonalAssistant"));` (or direct import if lazy loading is not used in this codebase — check existing import pattern)
|
|
- Add route inside `boardRoutes()` function, after the dashboard route: `<Route path="assistant" element={<PersonalAssistant />} />`
|
|
- Also add `<Route path="assistant/:conversationId" element={<PersonalAssistant />} />` for direct conversation linking
|
|
|
|
In `ui/src/components/Layout.tsx`:
|
|
- Add a sidebar NavLink for the assistant page
|
|
- Use `MessageCircle` or `Bot` icon from lucide-react (check which icons are already imported)
|
|
- Place it prominently — after Dashboard in the nav order
|
|
- Gate visibility using `useNexusMode()` — only show when `isAssistantEnabled` is true
|
|
- NavLink target: `/assistant`
|
|
- Label: "Assistant"
|
|
</action>
|
|
<read_first>
|
|
ui/src/App.tsx,
|
|
ui/src/components/Layout.tsx
|
|
</read_first>
|
|
<verify>
|
|
<automated>pnpm --filter @paperclipai/ui tsc --noEmit</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- grep -q "PersonalAssistant" ui/src/App.tsx
|
|
- grep -q "assistant" ui/src/App.tsx
|
|
- grep -q "assistant" ui/src/components/Layout.tsx
|
|
- grep -q "useNexusMode\|isAssistantEnabled" ui/src/components/Layout.tsx
|
|
</acceptance_criteria>
|
|
<done>
|
|
/assistant route exists and renders PersonalAssistant page. Sidebar shows Assistant link when mode is personal_ai or both, hidden when project_builder. TypeScript compiles clean.
|
|
</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
pnpm --filter @paperclipai/ui tsc --noEmit
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- PersonalAssistantPage renders chat interface when mode allows
|
|
- Route /assistant exists in board routes
|
|
- Sidebar link visible only when assistant mode enabled
|
|
- Mode redirect works (project_builder -> dashboard)
|
|
- TypeScript compiles without errors
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/33-persistent-memory/33-02-SUMMARY.md`
|
|
</output>
|