Add Contextual chat
This commit is contained in:
2
adiuvAI
2
adiuvAI
Submodule adiuvAI updated: 6aa7cb3d22...c1b1b289c1
@@ -0,0 +1,967 @@
|
|||||||
|
# Floating Chat Deprecation Sweep Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Delete every floating-chat code path across the adiuvAI Electron app — components, context, hooks, DOM attributes, stream branches, main-process methods, and shared-type artefacts — in five clean commits.
|
||||||
|
|
||||||
|
**Architecture:** The contextual sidebar (M4) fully replaces floating chat; floating is dead code with no live consumers. Each task targets one layer: (1) renderer components/context/hooks, (2) DOM data-attributes, (3) renderer hook logic, (4) main-process IPC/orchestrator, (5) store/localStorage keys sweep.
|
||||||
|
|
||||||
|
**Tech Stack:** TypeScript, React 19, Electron (main + preload + renderer), tRPC v11, Zod, electron-store.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pre-flight: baseline tsc check
|
||||||
|
|
||||||
|
- [ ] **Run tsc before touching anything**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /c/Users/PC-Roby/Documents/_adiuvai_workspace/adiuvAI
|
||||||
|
source ~/.nvm/nvm.sh && npx tsc --noEmit 2>&1 | tail -20
|
||||||
|
```
|
||||||
|
|
||||||
|
Record the number of pre-existing errors (expected: 0). Any errors here are pre-existing and not your fault.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task M6.1 — Delete FloatingChat component, context, hook + AppShell cleanup
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Delete: `src/renderer/components/ai/FloatingChat.tsx`
|
||||||
|
- Delete: `src/renderer/context/FloatingChatContext.tsx`
|
||||||
|
- Delete: `src/renderer/hooks/useDoubleClickAI.ts`
|
||||||
|
- Modify: `src/renderer/components/layout/AppShell.tsx`
|
||||||
|
- Modify: `src/renderer/components/projects/ProjectDetail.tsx`
|
||||||
|
- Modify: `src/renderer/components/timeline/TimelineGanttView.tsx`
|
||||||
|
- Modify: `src/renderer/routes/notes.$noteId.tsx`
|
||||||
|
- Modify: `src/renderer/routes/tasks.tsx`
|
||||||
|
|
||||||
|
### Context
|
||||||
|
|
||||||
|
Six files import from `FloatingChatContext` or `FloatingChat`. After deleting the three source files, all six must be cleaned up.
|
||||||
|
|
||||||
|
`ProjectDetail.tsx`, `TimelineGanttView.tsx`, `notes.$noteId.tsx`, and `tasks.tsx` import `useFloatingChat()` and call `registerSection`/`unregisterSection`. These are pure floating-chat wiring — they register DOM regions with the floating panel so it could anchor itself. With floating chat gone, these calls become dead code and must be removed entirely (no replacement needed; the contextual sidebar uses `useContextualScope` for scope awareness, which is already imported in tasks.tsx and ProjectDetail.tsx).
|
||||||
|
|
||||||
|
`AppShell.tsx` wraps the tree in `<FloatingChatProvider>` (line 151) and calls `useDoubleClickAI()` inside `AppShellInner` (line 166).
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
- [ ] **Step 1: Confirm all consumers before deletion**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rn "FloatingChat\|useFloatingChat\|FloatingChatProvider\|useDoubleClickAI" src/renderer/
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output matches: `AppShell.tsx`, `FloatingChat.tsx`, `FloatingChatContext.tsx`, `useDoubleClickAI.ts`, `ProjectDetail.tsx`, `TimelineGanttView.tsx`, `notes.$noteId.tsx`, `tasks.tsx`. If any unexpected file appears, stop and report before proceeding.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Delete the three source files**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git rm src/renderer/components/ai/FloatingChat.tsx
|
||||||
|
git rm src/renderer/context/FloatingChatContext.tsx
|
||||||
|
git rm src/renderer/hooks/useDoubleClickAI.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Clean AppShell.tsx**
|
||||||
|
|
||||||
|
Open `src/renderer/components/layout/AppShell.tsx`.
|
||||||
|
|
||||||
|
Remove line 28:
|
||||||
|
```ts
|
||||||
|
import { useDoubleClickAI } from '@/hooks/useDoubleClickAI';
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove lines 70–71:
|
||||||
|
```ts
|
||||||
|
import { FloatingChatPortal } from '@/components/ai/FloatingChat';
|
||||||
|
import { FloatingChatProvider } from '@/context/FloatingChatContext';
|
||||||
|
```
|
||||||
|
|
||||||
|
In `AppShell` (around line 149–163), change:
|
||||||
|
```tsx
|
||||||
|
export function AppShell({ children }: AppShellProps) {
|
||||||
|
return (
|
||||||
|
<FloatingChatProvider>
|
||||||
|
<ExpandedClientsProvider>
|
||||||
|
<TaskBriefingProvider>
|
||||||
|
<HeaderProvider>
|
||||||
|
<div className="flex w-full h-full">
|
||||||
|
<AppShellInner>{children}</AppShellInner>
|
||||||
|
</div>
|
||||||
|
</HeaderProvider>
|
||||||
|
</TaskBriefingProvider>
|
||||||
|
</ExpandedClientsProvider>
|
||||||
|
</FloatingChatProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
to:
|
||||||
|
```tsx
|
||||||
|
export function AppShell({ children }: AppShellProps) {
|
||||||
|
return (
|
||||||
|
<ExpandedClientsProvider>
|
||||||
|
<TaskBriefingProvider>
|
||||||
|
<HeaderProvider>
|
||||||
|
<div className="flex w-full h-full">
|
||||||
|
<AppShellInner>{children}</AppShellInner>
|
||||||
|
</div>
|
||||||
|
</HeaderProvider>
|
||||||
|
</TaskBriefingProvider>
|
||||||
|
</ExpandedClientsProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In `AppShellInner` (around line 166), remove:
|
||||||
|
```ts
|
||||||
|
useDoubleClickAI();
|
||||||
|
```
|
||||||
|
|
||||||
|
Search for `<FloatingChatPortal />` in the file (around line 288) and delete that line.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Clean ProjectDetail.tsx**
|
||||||
|
|
||||||
|
Open `src/renderer/components/projects/ProjectDetail.tsx`.
|
||||||
|
|
||||||
|
Remove line 24:
|
||||||
|
```ts
|
||||||
|
import { useFloatingChat } from '@/context/FloatingChatContext';
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove line 63:
|
||||||
|
```ts
|
||||||
|
const { registerSection, unregisterSection } = useFloatingChat();
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove the `useEffect` block that calls `registerSection`/`unregisterSection` (lines ~91–101):
|
||||||
|
```ts
|
||||||
|
useEffect(() => {
|
||||||
|
if (isLoading || !project) return;
|
||||||
|
registerSection({ id: 'project-summary', label: 'Project Summary', ref: summaryRef, projectId });
|
||||||
|
registerSection({ id: 'project-tasks', label: 'Tasks', ref: tasksRef, projectId });
|
||||||
|
registerSection({ id: 'project-notes', label: 'Notes', ref: notesRef, projectId });
|
||||||
|
return () => {
|
||||||
|
unregisterSection('project-summary');
|
||||||
|
unregisterSection('project-tasks');
|
||||||
|
unregisterSection('project-notes');
|
||||||
|
};
|
||||||
|
}, [projectId, isLoading, project, registerSection, unregisterSection]);
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Clean TimelineGanttView.tsx**
|
||||||
|
|
||||||
|
Open `src/renderer/components/timeline/TimelineGanttView.tsx`.
|
||||||
|
|
||||||
|
Remove line 31:
|
||||||
|
```ts
|
||||||
|
import { useFloatingChat } from '@/context/FloatingChatContext';
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove line 95:
|
||||||
|
```ts
|
||||||
|
const { registerSection, unregisterSection } = useFloatingChat();
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove the `useEffect` that calls `registerSection`/`unregisterSection` (lines ~107–110):
|
||||||
|
```ts
|
||||||
|
useEffect(() => {
|
||||||
|
registerSection({ id: sectionId, label: sectionLabel, ref: sectionRef, projectId });
|
||||||
|
return () => unregisterSection(sectionId);
|
||||||
|
}, [sectionId, sectionLabel, projectId, registerSection, unregisterSection]);
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: Clean notes.$noteId.tsx**
|
||||||
|
|
||||||
|
Open `src/renderer/routes/notes.$noteId.tsx`.
|
||||||
|
|
||||||
|
Remove line 29:
|
||||||
|
```ts
|
||||||
|
import { useFloatingChat } from '@/context/FloatingChatContext';
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove line 117:
|
||||||
|
```ts
|
||||||
|
const { registerSection, unregisterSection } = useFloatingChat();
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove the `useEffect` that calls `registerSection`/`unregisterSection` (lines ~119–128):
|
||||||
|
```ts
|
||||||
|
useEffect(() => {
|
||||||
|
registerSection({
|
||||||
|
id: 'note-editor',
|
||||||
|
label: 'Note Editor',
|
||||||
|
ref: editorRef,
|
||||||
|
projectId: noteProjectId,
|
||||||
|
anchorMode: 'right-margin',
|
||||||
|
});
|
||||||
|
return () => unregisterSection('note-editor');
|
||||||
|
}, [noteId, noteProjectId, registerSection, unregisterSection]);
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 7: Clean tasks.tsx**
|
||||||
|
|
||||||
|
Open `src/renderer/routes/tasks.tsx`.
|
||||||
|
|
||||||
|
Remove line 5:
|
||||||
|
```ts
|
||||||
|
import { useFloatingChat } from '@/context/FloatingChatContext';
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove line 18:
|
||||||
|
```ts
|
||||||
|
const { registerSection, unregisterSection } = useFloatingChat();
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove the `useEffect` that calls `registerSection`/`unregisterSection` (lines ~20–27):
|
||||||
|
```ts
|
||||||
|
useEffect(() => {
|
||||||
|
registerSection({ id: 'tasks-overview', label: 'Tasks Overview', ref: overviewRef });
|
||||||
|
registerSection({ id: 'tasks-list', label: 'Task List', ref: listRef });
|
||||||
|
return () => {
|
||||||
|
unregisterSection('tasks-overview');
|
||||||
|
unregisterSection('tasks-list');
|
||||||
|
};
|
||||||
|
}, [registerSection, unregisterSection]);
|
||||||
|
```
|
||||||
|
|
||||||
|
Also remove the `overviewRef` and `listRef` ref declarations if they are now unused (check whether they are still referenced by the JSX `ref=` attributes after M6.2 strips `data-ai-section`):
|
||||||
|
```ts
|
||||||
|
const overviewRef = useRef<HTMLDivElement>(null);
|
||||||
|
const listRef = useRef<HTMLDivElement>(null);
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: After M6.2 removes `data-ai-section` attributes, `ref={overviewRef}` and `ref={listRef}` in the JSX will also be gone, making the refs fully dead. Remove them here (or in M6.2 — just do it in whichever task you're in when you notice them).
|
||||||
|
|
||||||
|
- [ ] **Step 8: Type check**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source ~/.nvm/nvm.sh && npx tsc --noEmit 2>&1 | grep -i "error" | head -30
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: zero errors related to FloatingChat, FloatingChatContext, useDoubleClickAI. If any appear, locate the offending file and remove the import/usage.
|
||||||
|
|
||||||
|
- [ ] **Step 9: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/renderer/components/layout/AppShell.tsx \
|
||||||
|
src/renderer/components/projects/ProjectDetail.tsx \
|
||||||
|
src/renderer/components/timeline/TimelineGanttView.tsx \
|
||||||
|
src/renderer/routes/notes.\$noteId.tsx \
|
||||||
|
src/renderer/routes/tasks.tsx
|
||||||
|
git commit -m "$(cat <<'EOF'
|
||||||
|
refactor(contextual): delete FloatingChat, FloatingChatContext, useDoubleClickAI
|
||||||
|
|
||||||
|
Replaced by ContextualChatProvider + AdiuvaTriggerButton in M4.
|
||||||
|
Pre-1.0 clean removal — no deprecation period.
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task M6.2 — Strip all `data-ai-section` attributes
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src/renderer/components/projects/ProjectDetail.tsx`
|
||||||
|
- Modify: `src/renderer/components/timeline/TimelineGanttView.tsx`
|
||||||
|
- Modify: `src/renderer/routes/notes.$noteId.tsx`
|
||||||
|
- Modify: `src/renderer/routes/tasks.tsx`
|
||||||
|
|
||||||
|
### Context
|
||||||
|
|
||||||
|
`data-ai-section` was used by `useDoubleClickAI` to walk the DOM and find the nearest section anchor to open floating chat. Now that floating chat is gone, these attributes are purely dead markup. The contextual sidebar uses `scope` payloads, not DOM attributes.
|
||||||
|
|
||||||
|
Current occurrences (7 total):
|
||||||
|
- `ProjectDetail.tsx:538` — `data-ai-section="project-summary"`
|
||||||
|
- `ProjectDetail.tsx:620` — `data-ai-section="project-tasks"`
|
||||||
|
- `ProjectDetail.tsx:631` — `data-ai-section="project-notes"`
|
||||||
|
- `TimelineGanttView.tsx:239` — `data-ai-section={sectionId}`
|
||||||
|
- `notes.$noteId.tsx:291` — `data-ai-section="note-editor"`
|
||||||
|
- `tasks.tsx:42` — `data-ai-section="tasks-overview"`
|
||||||
|
- `tasks.tsx:61` — `data-ai-section="tasks-list"`
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
- [ ] **Step 1: List all occurrences**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rn "data-ai-section" src/renderer/
|
||||||
|
```
|
||||||
|
|
||||||
|
Confirm you see exactly the 7 occurrences listed above. If more appear, handle them too.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Remove from ProjectDetail.tsx**
|
||||||
|
|
||||||
|
For each JSX element with a `data-ai-section` prop, delete only that prop (keep `className` and all others). Example:
|
||||||
|
|
||||||
|
Find:
|
||||||
|
```tsx
|
||||||
|
<div
|
||||||
|
ref={summaryRef}
|
||||||
|
data-ai-section="project-summary"
|
||||||
|
className="..."
|
||||||
|
>
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```tsx
|
||||||
|
<div
|
||||||
|
ref={summaryRef}
|
||||||
|
className="..."
|
||||||
|
>
|
||||||
|
```
|
||||||
|
|
||||||
|
Repeat for `project-tasks` and `project-notes`.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Remove from TimelineGanttView.tsx**
|
||||||
|
|
||||||
|
Find the element at line ~239 and remove only the `data-ai-section={sectionId}` prop. Keep `ref={sectionRef}` and any other props.
|
||||||
|
|
||||||
|
Also check: after M6.1 removed `registerSection`/`unregisterSection`, there may now be `sectionRef`, `sectionId`, `sectionLabel` variables declared but unused. Remove any that are now dead. Check with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -n "sectionRef\|sectionId\|sectionLabel" src/renderer/components/timeline/TimelineGanttView.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
If these variables are only used by the removed `useEffect` and the now-removed `data-ai-section` attribute, delete their declarations too.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Remove from notes.$noteId.tsx**
|
||||||
|
|
||||||
|
Find the `<ScrollArea>` at line ~291:
|
||||||
|
```tsx
|
||||||
|
<ScrollArea ref={editorRef} data-ai-section="note-editor" className="flex-1 min-h-0">
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```tsx
|
||||||
|
<ScrollArea ref={editorRef} className="flex-1 min-h-0">
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: `editorRef` is still used by the existing scroll area ref, so keep it.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Remove from tasks.tsx**
|
||||||
|
|
||||||
|
Remove `data-ai-section="tasks-overview"` from the div at line ~42 and `data-ai-section="tasks-list"` from the div at line ~61. Also remove `ref={overviewRef}` and `ref={listRef}` from those elements if the refs were removed in M6.1.
|
||||||
|
|
||||||
|
If `overviewRef` and `listRef` are now unused (no JSX `ref=` and no other use), delete their `useRef` declarations too.
|
||||||
|
|
||||||
|
- [ ] **Step 6: Verify clean**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rn "data-ai-section" src/renderer/
|
||||||
|
echo "exit=$?"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: no output, `exit=1` (grep found nothing).
|
||||||
|
|
||||||
|
- [ ] **Step 7: Type check + commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source ~/.nvm/nvm.sh && npx tsc --noEmit 2>&1 | grep -i "error" | head -20
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: zero errors.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/renderer/components/projects/ProjectDetail.tsx \
|
||||||
|
src/renderer/components/timeline/TimelineGanttView.tsx \
|
||||||
|
src/renderer/routes/notes.\$noteId.tsx \
|
||||||
|
src/renderer/routes/tasks.tsx
|
||||||
|
git commit -m "$(cat <<'EOF'
|
||||||
|
refactor(contextual): strip all data-ai-section attributes
|
||||||
|
|
||||||
|
Section-anchoring obsolete now that there is no floating chat.
|
||||||
|
The contextual sidebar uses scope payload, not DOM attributes.
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task M6.3 — Drop `'floating'` from `useAIChat` + `ChatInputBox` + `useChatStream`
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src/renderer/hooks/useAIChat.ts`
|
||||||
|
- Modify: `src/renderer/hooks/useChatStream.ts`
|
||||||
|
- Modify: `src/renderer/components/ai/ChatInputBox.tsx`
|
||||||
|
- Modify: `src/renderer/components/brief/TaskBriefChat.tsx`
|
||||||
|
|
||||||
|
### Context
|
||||||
|
|
||||||
|
`useAIChat.ts` has `FloatingDomainSignal` type, `'floating'` in `UIChatContext.type` union, a `scope` field, a `'floating'` cache-key branch, `isFloating` logic in `handleSend`, `floating_domain` switch case, and `onDomainSignalRef`. All dead after M6.1 deleted `FloatingChat.tsx` which was the only consumer.
|
||||||
|
|
||||||
|
`useChatStream.ts` has a `floating_domain` case and the `onDomainSignal` option — kept during M2.1 explicitly "until M6 removes floating." Now is the time.
|
||||||
|
|
||||||
|
`ChatInputBox.tsx` has `'floating'` as a variant in `ChatInputBoxVariant` with its own style entry. This is a visual variant only — the type can be removed if nothing still passes `variant="floating"`. After `FloatingChat.tsx` is gone, nothing does.
|
||||||
|
|
||||||
|
`TaskBriefChat.tsx` passes `mode: 'floating'` to `chatMutation.mutate(...)`. After removing the floating mode from the tRPC schema (M6.4), this becomes a type error. Fix it here by removing `mode: 'floating'` and `scope` from the mutation call — task briefs will fall through to the default home orchestrator, or better: use `mode: 'contextual'` with the scope. Since task brief already passes `scope: { type: 'task', id: taskId }`, change `mode: 'floating'` to `mode: 'contextual'`.
|
||||||
|
|
||||||
|
`parseMutationsToEntityTags` and `TABLE_TO_ENTITY` in `useAIChat.ts` are still needed — `useChatStream.ts` imports `parseMutationsToEntityTags` from `useAIChat.ts`. Keep both exports.
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
- [ ] **Step 1: Edit useAIChat.ts**
|
||||||
|
|
||||||
|
Open `src/renderer/hooks/useAIChat.ts`.
|
||||||
|
|
||||||
|
**Delete lines 4–13** (the `FloatingDomainSignal` type):
|
||||||
|
```ts
|
||||||
|
export type FloatingDomainSignal =
|
||||||
|
| 'tasks'
|
||||||
|
| 'notes'
|
||||||
|
| 'timelines'
|
||||||
|
| 'projects'
|
||||||
|
| {
|
||||||
|
type: 'task' | 'timeline' | 'project' | 'note' | 'node';
|
||||||
|
id?: string | null;
|
||||||
|
section?: 'task' | 'timeline' | 'note' | null;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Replace the `UIChatContext` interface** (lines 23–31):
|
||||||
|
```ts
|
||||||
|
export interface UIChatContext {
|
||||||
|
type: 'global' | 'project' | 'floating';
|
||||||
|
projectId?: string;
|
||||||
|
/** For floating mode — the entity scope to pass to the backend. */
|
||||||
|
scope?: {
|
||||||
|
type: 'task' | 'project' | 'note' | 'timeline';
|
||||||
|
id?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
with:
|
||||||
|
```ts
|
||||||
|
export interface UIChatContext {
|
||||||
|
type: 'global' | 'project';
|
||||||
|
projectId?: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Delete the `UseAIChatOptions` interface** (lines 50–52):
|
||||||
|
```ts
|
||||||
|
interface UseAIChatOptions {
|
||||||
|
onDomainSignal?: (domain: FloatingDomainSignal) => void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Update the `useAIChat` function signature** — remove the `options` parameter:
|
||||||
|
```ts
|
||||||
|
export function useAIChat(defaultContext: UIChatContext, options?: UseAIChatOptions): UseAIChatReturn {
|
||||||
|
```
|
||||||
|
becomes:
|
||||||
|
```ts
|
||||||
|
export function useAIChat(defaultContext: UIChatContext): UseAIChatReturn {
|
||||||
|
```
|
||||||
|
|
||||||
|
**Update `getContextCacheKey`** — replace the entire function body:
|
||||||
|
```ts
|
||||||
|
function getContextCacheKey(ctx: UIChatContext): string {
|
||||||
|
if (ctx.type === 'global') return 'global';
|
||||||
|
if (ctx.type === 'project') return `project:${ctx.projectId ?? ''}`;
|
||||||
|
|
||||||
|
// Floating chat should keep a single continuous session while the panel is open,
|
||||||
|
// even when route/section context changes due floating-domain navigation.
|
||||||
|
return 'floating';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
with:
|
||||||
|
```ts
|
||||||
|
function getContextCacheKey(ctx: UIChatContext): string {
|
||||||
|
if (ctx.type === 'global') return 'global';
|
||||||
|
return `project:${ctx.projectId ?? ''}`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Update the `useMemo` for `contextCacheKey`** — remove `defaultContext.scope?.type` and `defaultContext.scope?.id` from deps:
|
||||||
|
```ts
|
||||||
|
const contextCacheKey = useMemo(
|
||||||
|
() => getContextCacheKey(defaultContext),
|
||||||
|
[defaultContext.type, defaultContext.projectId, defaultContext.scope?.type, defaultContext.scope?.id],
|
||||||
|
);
|
||||||
|
```
|
||||||
|
becomes:
|
||||||
|
```ts
|
||||||
|
const contextCacheKey = useMemo(
|
||||||
|
() => getContextCacheKey(defaultContext),
|
||||||
|
[defaultContext.type, defaultContext.projectId],
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Remove `onDomainSignalRef`** (lines 151–152):
|
||||||
|
```ts
|
||||||
|
const onDomainSignalRef = useRef(options?.onDomainSignal);
|
||||||
|
onDomainSignalRef.current = options?.onDomainSignal;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Remove the `floating_domain` case** from the `switch (event.type)` block (lines 237–239):
|
||||||
|
```ts
|
||||||
|
case 'floating_domain':
|
||||||
|
onDomainSignalRef.current?.(event.domain);
|
||||||
|
break;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Remove `isFloating` and the conditional spread** in `handleSend` (lines 249–259):
|
||||||
|
```ts
|
||||||
|
const isFloating = ctx.type === 'floating';
|
||||||
|
|
||||||
|
chatMutationRef.current.mutate(
|
||||||
|
{
|
||||||
|
requestId,
|
||||||
|
message: trimmed,
|
||||||
|
conversationHistory,
|
||||||
|
sessionId: sessionIdRef.current,
|
||||||
|
...(isFloating && ctx.scope
|
||||||
|
? { mode: 'floating' as const, scope: ctx.scope }
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
|
```
|
||||||
|
becomes:
|
||||||
|
```ts
|
||||||
|
chatMutationRef.current.mutate(
|
||||||
|
{
|
||||||
|
requestId,
|
||||||
|
message: trimmed,
|
||||||
|
conversationHistory,
|
||||||
|
sessionId: sessionIdRef.current,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Edit useChatStream.ts**
|
||||||
|
|
||||||
|
Open `src/renderer/hooks/useChatStream.ts`.
|
||||||
|
|
||||||
|
Remove `onDomainSignal` from `UseChatStreamArgs` interface (lines 17–18):
|
||||||
|
```ts
|
||||||
|
/** Optional: legacy floating_domain pivot signal. Kept until M6 removes floating. */
|
||||||
|
onDomainSignal?: (domain: unknown) => void;
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove `onDomainSignal` from the destructuring of `useChatStream`'s argument (line 25):
|
||||||
|
```ts
|
||||||
|
onDomainSignal,
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove `domainRef` declarations (lines 33–34):
|
||||||
|
```ts
|
||||||
|
const domainRef = useRef(onDomainSignal);
|
||||||
|
domainRef.current = onDomainSignal;
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove the `floating_domain` case from the switch block (lines 70–72):
|
||||||
|
```ts
|
||||||
|
case 'floating_domain':
|
||||||
|
domainRef.current?.(event.domain);
|
||||||
|
break;
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Edit ChatInputBox.tsx**
|
||||||
|
|
||||||
|
Open `src/renderer/components/ai/ChatInputBox.tsx`.
|
||||||
|
|
||||||
|
The `'floating'` variant in `ChatInputBoxVariant` (line 12) and its entry in `VARIANT_STYLES` (lines 30–35) should be removed since no live code passes `variant="floating"` any more.
|
||||||
|
|
||||||
|
Change:
|
||||||
|
```ts
|
||||||
|
type ChatInputBoxVariant = 'panel' | 'floating' | 'comment';
|
||||||
|
```
|
||||||
|
to:
|
||||||
|
```ts
|
||||||
|
type ChatInputBoxVariant = 'panel' | 'comment';
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove the `floating` entry from `VARIANT_STYLES` (lines 30–35):
|
||||||
|
```ts
|
||||||
|
floating: {
|
||||||
|
container: 'flex items-center gap-2 px-3 py-2.5',
|
||||||
|
textarea: 'flex-1 resize-none bg-transparent text-sm placeholder:text-muted-foreground/60 outline-none max-h-20 overflow-y-auto',
|
||||||
|
button: 'flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-sm transition-all hover:bg-primary/90 active:scale-95 disabled:opacity-30 disabled:cursor-not-allowed',
|
||||||
|
iconSize: 14,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
Also remove the comment about FloatingChat on line 52:
|
||||||
|
```ts
|
||||||
|
// Re-init when the cache key changes (context switches in FloatingChat).
|
||||||
|
```
|
||||||
|
Replace with a neutral comment or just remove the comment line.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Fix TaskBriefChat.tsx**
|
||||||
|
|
||||||
|
Open `src/renderer/components/brief/TaskBriefChat.tsx`.
|
||||||
|
|
||||||
|
At line ~174–184, change:
|
||||||
|
```ts
|
||||||
|
chatMutation.mutate(
|
||||||
|
{
|
||||||
|
requestId,
|
||||||
|
message: trimmed,
|
||||||
|
conversationHistory,
|
||||||
|
sessionId,
|
||||||
|
mode: 'floating',
|
||||||
|
scope: { type: 'task', id: taskId },
|
||||||
|
briefMode: true,
|
||||||
|
briefingContext: briefingText || undefined,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
to:
|
||||||
|
```ts
|
||||||
|
chatMutation.mutate(
|
||||||
|
{
|
||||||
|
requestId,
|
||||||
|
message: trimmed,
|
||||||
|
conversationHistory,
|
||||||
|
sessionId,
|
||||||
|
mode: 'contextual',
|
||||||
|
scope: { type: 'task', id: taskId },
|
||||||
|
briefMode: true,
|
||||||
|
briefingContext: briefingText || undefined,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Type check**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source ~/.nvm/nvm.sh && npx tsc --noEmit 2>&1 | grep -i "error" | head -30
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: zero errors. If tsc reports that `'floating'` is no longer valid for some type (from M6.4 not yet done), note it — the router schema still allows `'floating'` until M6.4. If tsc reports that `useAIChat` call sites are broken, check them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rn "useAIChat" src/renderer/
|
||||||
|
```
|
||||||
|
|
||||||
|
All call sites should be passing only `type: 'global'` or `type: 'project'` contexts after FloatingChat.tsx was deleted.
|
||||||
|
|
||||||
|
- [ ] **Step 6: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/renderer/hooks/useAIChat.ts \
|
||||||
|
src/renderer/hooks/useChatStream.ts \
|
||||||
|
src/renderer/components/ai/ChatInputBox.tsx \
|
||||||
|
src/renderer/components/brief/TaskBriefChat.tsx
|
||||||
|
git commit -m "$(cat <<'EOF'
|
||||||
|
refactor(contextual): drop 'floating' branch from useAIChat and useChatStream
|
||||||
|
|
||||||
|
UIChatContext is now 'global' | 'project' only. Floating domain
|
||||||
|
signal, scope field, and onDomainSignal callback removed. ChatInputBox
|
||||||
|
no longer defines floating variant. TaskBriefChat migrated to contextual mode.
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task M6.4 — Main process: drop `sendFloatingRequest`, `orchestrateFloating`, floating mode
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src/main/api/backend-client.ts`
|
||||||
|
- Modify: `src/main/ai/orchestrator.ts`
|
||||||
|
- Modify: `src/main/router/index.ts`
|
||||||
|
- Modify: `src/preload/trpc.ts`
|
||||||
|
- Modify: `src/renderer/lib/ipcLink.ts`
|
||||||
|
- Modify: `src/shared/api-types.ts`
|
||||||
|
|
||||||
|
### Context
|
||||||
|
|
||||||
|
`backend-client.ts` has `sendFloatingRequest` (lines 398–458) and a `floating_domain` case in its WS message handler (lines 1060–1063).
|
||||||
|
|
||||||
|
`orchestrator.ts` has `OrchestrateFloatingInput` interface (lines 40–49) and `orchestrateFloating` function (lines 142–173). It also imports `WsFloatingRequest` from shared types.
|
||||||
|
|
||||||
|
`router/index.ts` imports `orchestrateFloating` (line 16) and uses it at lines 950–960. The `mode` enum must change from `z.enum(['home', 'floating', 'contextual'])` to `z.enum(['contextual'])`.
|
||||||
|
|
||||||
|
`preload/trpc.ts` defines the `V3StreamEvent` union which includes `floating_domain` (lines 29–42).
|
||||||
|
|
||||||
|
`renderer/lib/ipcLink.ts` defines a duplicate `V3StreamEvent` type which also includes `floating_domain` (lines 16–33).
|
||||||
|
|
||||||
|
`shared/api-types.ts` defines `WsFloatingDomainSchema` (lines 217–228) and `WsFloatingDomain` type.
|
||||||
|
|
||||||
|
Check also whether `WsFloatingRequest` type is still needed by anything after removing `orchestrateFloating`:
|
||||||
|
```bash
|
||||||
|
grep -rn "WsFloatingRequest\|WsFloatingDomain" src/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
- [ ] **Step 1: Delete sendFloatingRequest from backend-client.ts**
|
||||||
|
|
||||||
|
Open `src/main/api/backend-client.ts`.
|
||||||
|
|
||||||
|
Delete the entire `sendFloatingRequest` method (lines ~394–458), from the JSDoc comment through the closing `}`.
|
||||||
|
|
||||||
|
Also delete the `floating_domain` case in the WS message handler (lines ~1060–1063):
|
||||||
|
```ts
|
||||||
|
case 'floating_domain': {
|
||||||
|
const listener = this.streamListeners.get(frame.data.requestId);
|
||||||
|
listener?.onDomain(frame.data.domain);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Also check whether `onDomain` is still used in `StreamListener` type or elsewhere. If `onDomain` callback is only referenced by `sendFloatingRequest` and the `floating_domain` case, delete the `onDomain` field from `StreamListener` too (search for `onDomain` to confirm all uses).
|
||||||
|
|
||||||
|
- [ ] **Step 2: Delete orchestrateFloating from orchestrator.ts**
|
||||||
|
|
||||||
|
Open `src/main/ai/orchestrator.ts`.
|
||||||
|
|
||||||
|
Delete lines 40–49 (`OrchestrateFloatingInput` interface):
|
||||||
|
```ts
|
||||||
|
interface OrchestrateFloatingInput {
|
||||||
|
message: string;
|
||||||
|
requestId?: string;
|
||||||
|
sessionId?: string;
|
||||||
|
scope: WsFloatingRequest['scope'];
|
||||||
|
conversationHistory?: WsFloatingRequest['conversationHistory'];
|
||||||
|
briefMode?: boolean;
|
||||||
|
briefingContext?: string;
|
||||||
|
sender?: Electron.WebContents;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Delete lines 1–16 of the import section's `WsFloatingRequest` import. Change:
|
||||||
|
```ts
|
||||||
|
import type { WsFloatingRequest } from '../../shared/api-types';
|
||||||
|
```
|
||||||
|
to nothing (remove the line entirely), since `WsFloatingRequest` is only used by `OrchestrateFloatingInput`.
|
||||||
|
|
||||||
|
Delete the entire `orchestrateFloating` function (lines 142–173):
|
||||||
|
```ts
|
||||||
|
export async function orchestrateFloating(input: OrchestrateFloatingInput): Promise<OrchestrateResult> {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Update the docstring at the top of the file (lines 1–10) — remove the reference to `sendFloatingRequest()`:
|
||||||
|
```
|
||||||
|
* 2. Delegates to BackendClient.sendHomeRequest() / sendFloatingRequest()
|
||||||
|
```
|
||||||
|
becomes:
|
||||||
|
```
|
||||||
|
* 2. Delegates to BackendClient.sendHomeRequest() / sendContextualRequest()
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Update router/index.ts**
|
||||||
|
|
||||||
|
Open `src/main/router/index.ts`.
|
||||||
|
|
||||||
|
Change line 16 — remove `orchestrateFloating` from the import:
|
||||||
|
```ts
|
||||||
|
import { orchestrate, orchestrateFloating, orchestrateContextual, orchestrateTaskBriefResearch, dailyBrief, getCachedBrief, invalidateBriefCache } from '../ai/orchestrator';
|
||||||
|
```
|
||||||
|
becomes:
|
||||||
|
```ts
|
||||||
|
import { orchestrate, orchestrateContextual, orchestrateTaskBriefResearch, dailyBrief, getCachedBrief, invalidateBriefCache } from '../ai/orchestrator';
|
||||||
|
```
|
||||||
|
|
||||||
|
Change line 933 — update the `mode` enum:
|
||||||
|
```ts
|
||||||
|
mode: z.enum(['home', 'floating', 'contextual']).optional(),
|
||||||
|
```
|
||||||
|
becomes:
|
||||||
|
```ts
|
||||||
|
mode: z.enum(['contextual']).optional(),
|
||||||
|
```
|
||||||
|
|
||||||
|
Delete the floating branch in the mutation handler (lines 950–960):
|
||||||
|
```ts
|
||||||
|
if (input.mode === 'floating' && input.scope) {
|
||||||
|
return await orchestrateFloating({
|
||||||
|
message: input.message,
|
||||||
|
requestId: input.requestId,
|
||||||
|
sessionId: input.sessionId,
|
||||||
|
scope: input.scope as Parameters<typeof orchestrateFloating>[0]['scope'],
|
||||||
|
conversationHistory: input.conversationHistory,
|
||||||
|
briefMode: input.briefMode,
|
||||||
|
briefingContext: input.briefingContext,
|
||||||
|
sender: ctx.sender,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting mutation handler should flow: `if contextual → orchestrateContextual`, else `→ orchestrate`.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Update preload/trpc.ts**
|
||||||
|
|
||||||
|
Open `src/preload/trpc.ts`.
|
||||||
|
|
||||||
|
Remove the `floating_domain` case from the `V3StreamEvent` union (lines 29–42):
|
||||||
|
```ts
|
||||||
|
| {
|
||||||
|
type: 'floating_domain';
|
||||||
|
requestId: string;
|
||||||
|
domain:
|
||||||
|
| 'tasks'
|
||||||
|
| 'notes'
|
||||||
|
| 'timelines'
|
||||||
|
| 'projects'
|
||||||
|
| {
|
||||||
|
type: 'task' | 'timeline' | 'project' | 'note' | 'node';
|
||||||
|
id?: string | null;
|
||||||
|
section?: 'task' | 'timeline' | 'note' | null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `V3StreamEvent` union becomes:
|
||||||
|
```ts
|
||||||
|
type V3StreamEvent =
|
||||||
|
| { type: 'stream_start'; requestId: string }
|
||||||
|
| { type: 'stream_text'; requestId: string; chunk: string }
|
||||||
|
| { type: 'stream_end'; requestId: string; mutations?: unknown[] };
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Update renderer/lib/ipcLink.ts**
|
||||||
|
|
||||||
|
Open `src/renderer/lib/ipcLink.ts`.
|
||||||
|
|
||||||
|
Remove the `floating_domain` case from the `V3StreamEvent` union (lines 16–33) the same way as done in preload. The type becomes:
|
||||||
|
```ts
|
||||||
|
type V3StreamEvent =
|
||||||
|
| { type: 'stream_start'; requestId: string }
|
||||||
|
| { type: 'stream_text'; requestId: string; chunk: string }
|
||||||
|
| { type: 'stream_end'; requestId: string; mutations?: unknown[] };
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: Update shared/api-types.ts**
|
||||||
|
|
||||||
|
Open `src/shared/api-types.ts`.
|
||||||
|
|
||||||
|
Check whether `WsFloatingDomainSchema` / `WsFloatingDomain` are imported anywhere:
|
||||||
|
```bash
|
||||||
|
grep -rn "WsFloatingDomain\|WsFloatingRequest" src/
|
||||||
|
```
|
||||||
|
|
||||||
|
If `WsFloatingRequest` is imported only by the now-deleted orchestrator import, and `WsFloatingDomain` is imported nowhere, delete both from `shared/api-types.ts`:
|
||||||
|
- Delete `WsFloatingDomainSchema` Zod object (lines 217–228)
|
||||||
|
- Delete `export type WsFloatingDomain = z.infer<typeof WsFloatingDomainSchema>;` (line 229)
|
||||||
|
- If `WsFloatingRequest` type/schema exists, delete it too (search for it in the file)
|
||||||
|
|
||||||
|
- [ ] **Step 7: Sweep for any remaining floating references in main**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rn "floating\|Floating" src/main/ src/preload/ | grep -v node_modules | grep -v "\.md:"
|
||||||
|
```
|
||||||
|
|
||||||
|
Any remaining references to floating in these directories should be removed. Common residuals:
|
||||||
|
- `onDomain` callback type in `StreamListener` (if `sendFloatingRequest` was its only consumer)
|
||||||
|
- Stale comments in `backend-client.ts` mentioning floating
|
||||||
|
|
||||||
|
- [ ] **Step 8: Type check**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source ~/.nvm/nvm.sh && npx tsc --noEmit 2>&1 | grep -i "error" | head -30
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: zero errors. The `TaskBriefChat.tsx` now sends `mode: 'contextual'` which is valid per the updated schema.
|
||||||
|
|
||||||
|
- [ ] **Step 9: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/main/api/backend-client.ts \
|
||||||
|
src/main/ai/orchestrator.ts \
|
||||||
|
src/main/router/index.ts \
|
||||||
|
src/preload/trpc.ts \
|
||||||
|
src/renderer/lib/ipcLink.ts \
|
||||||
|
src/shared/api-types.ts
|
||||||
|
git commit -m "$(cat <<'EOF'
|
||||||
|
refactor(contextual): main process drops sendFloatingRequest and floating mode
|
||||||
|
|
||||||
|
ai.chat tRPC procedure now accepts mode='contextual' (or unset for home).
|
||||||
|
Orchestrator loses the floating delegation branch. Backend client method
|
||||||
|
and WsFloatingDomain shared type removed.
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task M6.8 — Sweep electron-store and localStorage `'floating'` keys
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Inspect: `src/main/store.ts`
|
||||||
|
- Inspect: `src/renderer/` (any localStorage usage)
|
||||||
|
|
||||||
|
### Context
|
||||||
|
|
||||||
|
`src/main/store.ts` defines the electron-store schema — no `floating.*` keys exist in the current schema (verified: `AppSettings` has `sidebarCollapsed`, `encryptedTokens`, `backendUrl`, `deviceId`, `dailyBriefCache`, `localAgents`, `formatPrefs`, `uiLanguage`, `timelineZoom`). No floating keys.
|
||||||
|
|
||||||
|
This task is a verification sweep. If nothing is found, the commit is skipped.
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
- [ ] **Step 1: Search for any floating.* key usage**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rn "floating\." src/main/ src/preload/ src/renderer/ | grep -v node_modules | grep -v "\.md:"
|
||||||
|
```
|
||||||
|
|
||||||
|
Also check localStorage:
|
||||||
|
```bash
|
||||||
|
grep -rn "localStorage" src/renderer/ | grep -v node_modules | grep "float"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Decision point**
|
||||||
|
|
||||||
|
If Step 1 returns NO results (or only results already cleaned by M6.1–M6.4), this task is a no-op. Skip the commit and note in the final report: "M6.8: no floating.* store or localStorage keys found — no commit needed."
|
||||||
|
|
||||||
|
If Step 1 returns results with actual floating key reads/writes in store.ts or localStorage calls:
|
||||||
|
- Delete the key from `AppSettings` interface and the `defaults` object in `store.ts`
|
||||||
|
- Delete any `localStorage.getItem('floating.*')` or `setItem('floating.*', ...)` calls
|
||||||
|
|
||||||
|
- [ ] **Step 3: Conditional commit**
|
||||||
|
|
||||||
|
Only run this if changes were made in Step 2:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add -A
|
||||||
|
git status --short # confirm what's staged
|
||||||
|
git commit -m "$(cat <<'EOF'
|
||||||
|
chore(contextual): purge residual 'floating' keys from store and renderer
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Final Self-Review Checklist
|
||||||
|
|
||||||
|
After all commits, run these verification checks and paste the output into your report:
|
||||||
|
|
||||||
|
- [ ] **FloatingChat imports gone**
|
||||||
|
```bash
|
||||||
|
grep -rn "FloatingChat\|useFloatingChat\|FloatingChatProvider\|useDoubleClickAI" src/renderer/
|
||||||
|
```
|
||||||
|
Expected: no output.
|
||||||
|
|
||||||
|
- [ ] **data-ai-section gone**
|
||||||
|
```bash
|
||||||
|
grep -rn "data-ai-section" src/renderer/
|
||||||
|
```
|
||||||
|
Expected: no output.
|
||||||
|
|
||||||
|
- [ ] **floating string in renderer hooks**
|
||||||
|
```bash
|
||||||
|
grep -rn "'floating'" src/renderer/hooks/
|
||||||
|
```
|
||||||
|
Expected: no output (sidebar.tsx uses `"floating"` as a layout variant — that is unrelated and harmless).
|
||||||
|
|
||||||
|
- [ ] **UIChatContext type**
|
||||||
|
```bash
|
||||||
|
grep -n "type:" src/renderer/hooks/useAIChat.ts | head -5
|
||||||
|
```
|
||||||
|
Expected: `'global' | 'project'` only.
|
||||||
|
|
||||||
|
- [ ] **tRPC schema**
|
||||||
|
```bash
|
||||||
|
grep -n "floating" src/main/router/index.ts
|
||||||
|
```
|
||||||
|
Expected: no output.
|
||||||
|
|
||||||
|
- [ ] **sendFloatingRequest gone**
|
||||||
|
```bash
|
||||||
|
grep -rn "sendFloatingRequest\|orchestrateFloating" src/main/
|
||||||
|
```
|
||||||
|
Expected: no output.
|
||||||
|
|
||||||
|
- [ ] **Final tsc**
|
||||||
|
```bash
|
||||||
|
source ~/.nvm/nvm.sh && npx tsc --noEmit 2>&1 | grep -c "error TS"
|
||||||
|
```
|
||||||
|
Expected: `0`
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
19681
graphify-out/graph.json
19681
graphify-out/graph.json
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user