Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .kilo/skills/kilo-mcp/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ to send platform feedback and bug reports rather than a support channel.
The first path segment names an area. Search to learn an area's vocabulary:
each row's `summary` and `tags` are what the search matches.

**836 procedures** — **357 queries**, **479 mutations** — under **49 prefixes**.
**838 procedures** — **359 queries**, **479 mutations** — under **49 prefixes**.

| Prefix | Procedures | Queries | Mutations |
|---|---:|---:|---:|
Expand All @@ -63,8 +63,8 @@ each row's `summary` and `tags` are what the search matches.
| `securityAgent` | 26 | 15 | 11 |
| `kiloPass` | 21 | 11 | 10 |
| `githubPrReview` | 20 | 6 | 14 |
| `cliSessionsV2` | 19 | 12 | 7 |
| `githubApps` | 19 | 9 | 10 |
| `cliSessionsV2` | 17 | 10 | 7 |
| `appBuilder` | 16 | 6 | 10 |
| `providerReview` | 16 | 8 | 8 |
| `todos` | 16 | 6 | 10 |
Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/components/cloud-agent-next/ChatSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
useRef,
useState,
type DragEvent,
type ReactNode,
} from 'react';
import {
SquarePen,
Expand Down Expand Up @@ -110,6 +111,7 @@ type ChatSidebarProps = {
onProjectChange?: (gitUrls: string[]) => void;
recentProjects?: Array<{ gitUrl: string; displayName: string }>;
workspaceFolders?: WorkspaceFolderController;
workspaceCleanup?: ReactNode;
};

type WorktreeFolderControls = {
Expand Down Expand Up @@ -666,6 +668,7 @@ export function ChatSidebar({
onProjectChange,
recentProjects = [],
workspaceFolders,
workspaceCleanup,
}: ChatSidebarProps) {
const router = useRouter();
const pathname = usePathname();
Expand Down Expand Up @@ -1111,6 +1114,8 @@ export function ChatSidebar({
</div>
</div>

{workspaceCleanup}

{/* Collapsible search */}
{showSearch && (
<div className="border-b px-3 py-2">
Expand Down
85 changes: 59 additions & 26 deletions apps/web/src/components/cloud-agent-next/CloudSidebarLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ import {
} from './local-sessions/local-session';
import { sendLocalSessionRequest } from './local-sessions/local-session-request';
import { localSessionsStorageKey } from './local-sessions/local-session-storage';
import { useWorktreeCleanup } from './hooks/useWorktreeCleanup';
import { MergedWorktreeCleanup } from './MergedWorktreeCleanup';

// Context for children to toggle the mobile sidebar sheet
type WorktreeChatTabs = {
Expand Down Expand Up @@ -803,6 +805,50 @@ function CloudSidebarLayoutContent({
[organizationId, queryClient, renameWorktree, trpc]
);

const handleWorktreeDeleted = useCallback(
async (worktreeId: string, deletedSessionIds: string[]) => {
await Promise.all(
deletedSessionIds.map(sessionId =>
removeDeletedSession({
sessionId,
queryClient,
trpc,
setDbSessions,
deleteSessionFromStore,
})
)
);
forgetWorktreeTabs(worktreeId, deletedSessionIds);
const redirect = getWorktreeDeletionRedirect(
new URL(window.location.href),
worktreeId,
deletedSessionIds,
organizationId
);
if (redirect) router.push(redirect);
void invalidateSessionQueries({ queryClient, trpc });
void queryClient.invalidateQueries(trpc.workspaceFolders.list.pathFilter());
},
[
deleteSessionFromStore,
forgetWorktreeTabs,
organizationId,
queryClient,
router,
setDbSessions,
trpc,
]
);
const cleanup = useWorktreeCleanup({ organizationId, onDeleted: handleWorktreeDeleted });
const workspaceCleanup = (
<MergedWorktreeCleanup
organizationId={organizationId}
cleanup={cleanup.data}
statusError={cleanup.error}
statusLoading={cleanup.isPending}
/>
);

const handleConfirmWorktreeDelete = useCallback(() => {
const worktreeId = worktreePendingDeletion;
if (!worktreeId || deletingWorktreeIds.has(worktreeId)) return;
Expand All @@ -816,27 +862,7 @@ function CloudSidebarLayoutContent({
worktreeId: cloudAgentWorktreeIdSchema.parse(worktreeId),
organizationId: organizationId ?? null,
});
await Promise.all(
deletedSessionIds.map(sessionId =>
removeDeletedSession({
sessionId,
queryClient,
trpc,
setDbSessions,
deleteSessionFromStore,
})
)
);
forgetWorktreeTabs(worktreeId, deletedSessionIds);
const redirect = getWorktreeDeletionRedirect(
new URL(window.location.href),
worktreeId,
deletedSessionIds,
organizationId
);
if (redirect) router.push(redirect);
void invalidateSessionQueries({ queryClient, trpc });
void queryClient.invalidateQueries(trpc.workspaceFolders.list.pathFilter());
await handleWorktreeDeleted(worktreeId, deletedSessionIds);
toast.success('Worktree deleted');
} catch (error) {
toast.error('Failed to delete worktree', { description: formatSessionError(error) });
Expand All @@ -851,19 +877,24 @@ function CloudSidebarLayoutContent({
}
})();
}, [
deleteSessionFromStore,
deleteWorktree,
deletingWorktreeIds,
forgetWorktreeTabs,
handleWorktreeDeleted,
organizationId,
queryClient,
router,
setDbSessions,
trpc,
worktreePendingDeletion,
]);

const deletingWorktreeIdList = useMemo(() => [...deletingWorktreeIds], [deletingWorktreeIds]);
const deletingWorktreeIdList = useMemo(
() => [
...deletingWorktreeIds,
...(cleanup.data?.items
.filter(item => item.status === 'pending' || item.status === 'deleting')
.map(item => item.worktreeId) ?? []),
],
[cleanup.data, deletingWorktreeIds]
);
const toggleMobileSidebar = useCallback(() => setMobileSheetOpen(prev => !prev), []);
const sidebarContext = useMemo(
() => ({
Expand Down Expand Up @@ -922,6 +953,7 @@ function CloudSidebarLayoutContent({
<ChatSidebar
key={`mobile:${currentUserId}:${organizationId ?? 'personal'}`}
workspaceFolders={sidebarWorkspaceFolders}
workspaceCleanup={workspaceCleanup}
sessions={sidebarSessions}
currentSessionId={currentSessionId}
selectedWorktreeId={selectedWorktreeId}
Expand Down Expand Up @@ -957,6 +989,7 @@ function CloudSidebarLayoutContent({
<ChatSidebar
key={`desktop:${currentUserId}:${organizationId ?? 'personal'}`}
workspaceFolders={sidebarWorkspaceFolders}
workspaceCleanup={workspaceCleanup}
sessions={sidebarSessions}
currentSessionId={currentSessionId}
selectedWorktreeId={selectedWorktreeId}
Expand Down
Loading
Loading