fix: typescript errors
This commit is contained in:
@@ -24,3 +24,15 @@ repos:
|
||||
entry: make lint-web
|
||||
language: system
|
||||
pass_filenames: false
|
||||
|
||||
- id: web-typecheck
|
||||
name: Web typecheck
|
||||
entry: make typecheck-web
|
||||
language: system
|
||||
pass_filenames: false
|
||||
|
||||
- id: typecheck
|
||||
name: Typecheck all apps
|
||||
entry: make typecheck
|
||||
language: system
|
||||
pass_filenames: false
|
||||
|
||||
@@ -198,6 +198,16 @@ fmt-web:
|
||||
@echo "Formatting web code..."
|
||||
@cd $(APPS_DIR) && $(PNPM) --filter @kandev/web lint -- --fix || true
|
||||
|
||||
.PHONY: typecheck-web
|
||||
typecheck-web:
|
||||
@echo "Type-checking web app..."
|
||||
@cd $(APPS_DIR) && $(PNPM) --filter @kandev/web exec tsc -p tsconfig.json --noEmit
|
||||
|
||||
.PHONY: typecheck
|
||||
typecheck:
|
||||
@echo "Type-checking all apps..."
|
||||
@cd $(APPS_DIR) && $(PNPM) -r exec tsc -p tsconfig.json --noEmit
|
||||
|
||||
#
|
||||
# Cleanup
|
||||
#
|
||||
|
||||
@@ -159,13 +159,14 @@ func main() {
|
||||
log.Warn("Failed to initialize Docker client - agent features will be disabled", zap.Error(err))
|
||||
dockerClient = nil
|
||||
} else {
|
||||
defer func() {
|
||||
_ = dockerClient.Close()
|
||||
}()
|
||||
if err := dockerClient.Ping(ctx); err != nil {
|
||||
log.Warn("Docker daemon not available - agent features will be disabled", zap.Error(err))
|
||||
_ = dockerClient.Close()
|
||||
dockerClient = nil
|
||||
} else {
|
||||
defer func() {
|
||||
_ = dockerClient.Close()
|
||||
}()
|
||||
log.Info("Connected to Docker daemon")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export function KanbanWithPreview() {
|
||||
state: task.state,
|
||||
description: task.description,
|
||||
position: task.position,
|
||||
repositoryUrl: task.repositoryUrl,
|
||||
repositoryId: task.repositoryId,
|
||||
};
|
||||
}, [selectedTaskId, kanbanTasks]);
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import { IconX, IconCircleCheck, IconCircleX, IconLoader2, IconAlertTriangle, Ic
|
||||
import { Button } from "@kandev/ui/button";
|
||||
import { Badge } from "@kandev/ui/badge";
|
||||
import { getRepositoryDisplayName } from "@/lib/utils";
|
||||
import { useAppStore } from "@/components/state-provider";
|
||||
import { useMemo } from "react";
|
||||
import type { Task } from "./kanban-card";
|
||||
|
||||
interface TaskPreviewPanelProps {
|
||||
@@ -66,6 +68,15 @@ function getStateDisplay(state?: string) {
|
||||
}
|
||||
|
||||
export function TaskPreviewPanel({ task, onClose, onMaximize }: TaskPreviewPanelProps) {
|
||||
const repositoriesByWorkspace = useAppStore((state) => state.repositories.itemsByWorkspaceId);
|
||||
const repository = useMemo(() => {
|
||||
if (!task?.repositoryId) return null;
|
||||
return Object.values(repositoriesByWorkspace)
|
||||
.flat()
|
||||
.find((repo) => repo.id === task.repositoryId) ?? null;
|
||||
}, [repositoriesByWorkspace, task]);
|
||||
const repoName = getRepositoryDisplayName(repository?.local_path);
|
||||
|
||||
if (!task) {
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col border-l bg-background">
|
||||
@@ -83,7 +94,6 @@ export function TaskPreviewPanel({ task, onClose, onMaximize }: TaskPreviewPanel
|
||||
);
|
||||
}
|
||||
|
||||
const repoName = getRepositoryDisplayName(task.repositoryUrl);
|
||||
const stateDisplay = getStateDisplay(task.state);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import type { ReactElement } from 'react';
|
||||
import type { Message } from '@/lib/types/http';
|
||||
import { ChatMessage } from '@/components/task/chat/messages/chat-message';
|
||||
import { StatusMessage } from '@/components/task/chat/messages/status-message';
|
||||
@@ -13,7 +14,7 @@ type AdapterContext = {
|
||||
|
||||
type MessageAdapter = {
|
||||
matches: (comment: Message, ctx: AdapterContext) => boolean;
|
||||
render: (comment: Message, ctx: AdapterContext) => JSX.Element;
|
||||
render: (comment: Message, ctx: AdapterContext) => ReactElement;
|
||||
};
|
||||
|
||||
const adapters: MessageAdapter[] = [
|
||||
|
||||
@@ -13,13 +13,13 @@ function resolveDiffPayload(diff: unknown): DiffPayload | null {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(diff)) {
|
||||
return { hunks: diff };
|
||||
return { hunks: diff.map((hunk) => String(hunk)) };
|
||||
}
|
||||
if (typeof diff === 'object' && diff !== null) {
|
||||
const candidate = diff as Partial<DiffPayload>;
|
||||
if (Array.isArray(candidate.hunks)) {
|
||||
return {
|
||||
hunks: candidate.hunks,
|
||||
hunks: candidate.hunks.map((hunk) => String(hunk)),
|
||||
oldFile: candidate.oldFile,
|
||||
newFile: candidate.newFile,
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ export type RichMetadata = {
|
||||
};
|
||||
|
||||
export type DiffPayload = {
|
||||
hunks: unknown[];
|
||||
hunks: string[];
|
||||
oldFile?: { fileName?: string; fileLang?: string };
|
||||
newFile?: { fileName?: string; fileLang?: string };
|
||||
};
|
||||
|
||||
@@ -177,7 +177,6 @@ export function TaskChatPanel({
|
||||
const trimmed = messageInput.trim();
|
||||
if (!trimmed || isSending) return;
|
||||
setIsSending(true);
|
||||
setIsAwaitingResponse(true);
|
||||
flushSync(() => {
|
||||
setMessageInput('');
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ export function useKanbanPreview(options: UseKanbanPreviewOptions = {}) {
|
||||
// Always start with default values to avoid hydration mismatch
|
||||
const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [previewWidthPx, setPreviewWidthPx] = useState(PREVIEW_PANEL.DEFAULT_WIDTH_PX);
|
||||
const [previewWidthPx, setPreviewWidthPx] = useState<number>(PREVIEW_PANEL.DEFAULT_WIDTH_PX);
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// Load persisted state from localStorage AFTER hydration
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { getWebSocketClient } from '@/lib/ws/connection';
|
||||
import { useAppStore, useAppStoreApi } from '@/components/state-provider';
|
||||
import type { Message } from '@/lib/types/http';
|
||||
import type { AgentSessionState } from '@/lib/types/http';
|
||||
import type { AgentSessionState, Message } from '@/lib/types/http';
|
||||
|
||||
interface UseTaskMessagesReturn {
|
||||
isLoading: boolean;
|
||||
@@ -130,8 +129,8 @@ export function useTaskMessages(
|
||||
if (!agentSessionId || !agentSessionState || !taskId) return;
|
||||
if (hasAgentMessage) return;
|
||||
|
||||
const terminalStates: AgentSessionState[] = ['WAITING_FOR_INPUT', 'COMPLETED', 'FAILED'];
|
||||
if (!terminalStates.includes(agentSessionState)) {
|
||||
const terminalStates = new Set<AgentSessionState>(['WAITING_FOR_INPUT', 'COMPLETED', 'FAILED']);
|
||||
if (!terminalStates.has(agentSessionState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { MODIFIER_KEYS, KEYS, SHORTCUTS } from './constants';
|
||||
import { MODIFIER_KEYS, KEYS, SHORTCUTS, KeyboardShortcut } from './constants';
|
||||
|
||||
describe('MODIFIER_KEYS', () => {
|
||||
it('defines all modifier keys', () => {
|
||||
@@ -69,8 +69,9 @@ describe('SHORTCUTS', () => {
|
||||
|
||||
describe('CANCEL', () => {
|
||||
it('uses Escape key without modifiers', () => {
|
||||
expect(SHORTCUTS.CANCEL.key).toBe('Escape');
|
||||
expect(SHORTCUTS.CANCEL.modifiers).toBeUndefined();
|
||||
const cancel = SHORTCUTS.CANCEL as KeyboardShortcut;
|
||||
expect(cancel.key).toBe('Escape');
|
||||
expect(cancel.modifiers).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -110,9 +111,10 @@ describe('SHORTCUTS', () => {
|
||||
|
||||
it('all shortcuts with modifiers have valid modifier properties', () => {
|
||||
Object.values(SHORTCUTS).forEach((shortcut) => {
|
||||
if (shortcut.modifiers) {
|
||||
const typedShortcut = shortcut as KeyboardShortcut;
|
||||
if (typedShortcut.modifiers) {
|
||||
const validModifiers = ['ctrl', 'cmd', 'alt', 'shift', 'ctrlOrCmd'];
|
||||
Object.keys(shortcut.modifiers).forEach((modifier) => {
|
||||
Object.keys(typedShortcut.modifiers).forEach((modifier) => {
|
||||
expect(validModifiers).toContain(modifier);
|
||||
});
|
||||
}
|
||||
@@ -141,4 +143,3 @@ describe('Type definitions', () => {
|
||||
expect(shortcut3.modifiers?.ctrl).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ReactNode } from 'react';
|
||||
import type {
|
||||
Agent,
|
||||
AgentDiscovery,
|
||||
AgentSessionState,
|
||||
Branch,
|
||||
Environment,
|
||||
Executor,
|
||||
@@ -171,7 +172,7 @@ export type AppState = {
|
||||
gitStatus: GitStatusState;
|
||||
connection: ConnectionState;
|
||||
messages: MessagesState;
|
||||
agentSessionStatesByTaskId: Record<string, string>;
|
||||
agentSessionStatesByTaskId: Record<string, AgentSessionState>;
|
||||
hydrate: (state: Partial<AppState>) => void;
|
||||
setActiveWorkspace: (workspaceId: string | null) => void;
|
||||
setWorkspaces: (workspaces: WorkspaceState['items']) => void;
|
||||
@@ -201,7 +202,7 @@ export type AppState = {
|
||||
prependMessages: (messages: Message[], meta?: { hasMore?: boolean; oldestCursor?: string | null }) => void;
|
||||
setMessagesMetadata: (meta: { hasMore?: boolean; isLoading?: boolean; oldestCursor?: string | null }) => void;
|
||||
setMessagesLoading: (loading: boolean) => void;
|
||||
setAgentSessionState: (taskId: string, state: string) => void;
|
||||
setAgentSessionState: (taskId: string, state: AgentSessionState) => void;
|
||||
setGitStatus: (taskId: string, gitStatus: Omit<GitStatusState, 'taskId'>) => void;
|
||||
clearGitStatus: () => void;
|
||||
bumpAgentProfilesVersion: () => void;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { StoreApi } from 'zustand';
|
||||
import type { AppState } from '@/lib/state/store';
|
||||
import type { WsHandlers } from '@/lib/ws/handlers/types';
|
||||
import type { AgentSessionState } from '@/lib/types/http';
|
||||
|
||||
export function registerAgentSessionHandlers(store: StoreApi<AppState>): WsHandlers {
|
||||
return {
|
||||
@@ -9,7 +10,7 @@ export function registerAgentSessionHandlers(store: StoreApi<AppState>): WsHandl
|
||||
if (!payload?.task_id || !payload?.new_state) {
|
||||
return;
|
||||
}
|
||||
store.getState().setAgentSessionState(payload.task_id, payload.new_state);
|
||||
store.getState().setAgentSessionState(payload.task_id, payload.new_state as AgentSessionState);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user