From 61ef224ec75b24cffaabeff37030b0634df2889a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Thu, 19 Feb 2026 22:18:01 +0000 Subject: [PATCH] style: fix format issues (#255) --- .github/workflows/backend-tests.yml | 33 + .github/workflows/frontend-tests.yml | 40 + .gitignore | 1 + .pre-commit-config.yaml | 14 + Makefile | 10 +- apps/.prettierignore | 5 + apps/backend/cmd/kandev/gateway.go | 2 +- apps/backend/cmd/kandev/helpers.go | 6 +- apps/backend/cmd/kandev/worktree.go | 2 +- .../backend/cmd/mock-agent/mock_agent_test.go | 10 +- apps/backend/cmd/mock-agent/types.go | 48 +- apps/backend/internal/agent/agents/amp.go | 4 +- apps/backend/internal/agent/agents/auggie.go | 12 +- .../internal/agent/agents/auggie_test.go | 12 +- .../internal/agent/agents/claude_code.go | 4 +- apps/backend/internal/agent/agents/codex.go | 5 +- apps/backend/internal/agent/agents/copilot.go | 5 +- apps/backend/internal/agent/agents/gemini.go | 4 +- apps/backend/internal/agent/agents/helpers.go | 1 - apps/backend/internal/agent/agents/mock.go | 10 +- .../backend/internal/agent/agents/opencode.go | 4 +- .../internal/agent/controller/errors.go | 1 - .../agent/credentials/augment_provider.go | 1 - .../agent/credentials/env_provider.go | 1 - .../agent/credentials/file_provider.go | 1 - .../internal/agent/credentials/manager.go | 1 - apps/backend/internal/agent/dto/dto.go | 7 +- .../internal/agent/handlers/git_handlers.go | 1 - .../internal/agent/handlers/handlers.go | 1 - .../agent/handlers/workspace_file_handlers.go | 6 +- .../internal/agent/lifecycle/container.go | 2 +- .../internal/agent/lifecycle/event_types.go | 8 +- .../agent/lifecycle/execution_store.go | 2 - .../agent/lifecycle/manager_events.go | 1 - .../agent/lifecycle/manager_launch.go | 1 - .../agent/lifecycle/runtime_registry_test.go | 2 - .../internal/agent/lifecycle/session.go | 2 +- .../agent/lifecycle/session_history.go | 18 +- .../internal/agent/lifecycle/session_test.go | 4 +- .../internal/agent/registry/registry_test.go | 10 +- .../settings/controller/controller_test.go | 1 - .../backend/internal/agentctl/client/agent.go | 1 + .../agentctl/client/launcher/launcher.go | 2 - .../internal/agentctl/server/acp/client.go | 1 - .../agentctl/server/adapter/amp_adapter.go | 2 +- .../server/adapter/copilot_adapter.go | 6 +- .../adapter/transport/codex/normalize.go | 1 - .../streamjson/streamjson_permissions.go | 1 - .../agentctl/server/instance/instance.go | 1 - .../agentctl/server/mcp/backend_client.go | 1 - .../internal/agentctl/server/mcp/handlers.go | 1 - .../agentctl/server/process/cmdline_test.go | 4 +- .../server/process/interactive_lifecycle.go | 12 +- .../server/process/interactive_runner.go | 38 +- .../agentctl/server/process/manager_test.go | 6 +- .../agentctl/server/process/procattr_linux.go | 1 - .../agentctl/server/process/procattr_unix.go | 1 - .../server/process/procattr_windows.go | 1 - .../agentctl/server/process/pty_windows.go | 1 - .../agentctl/server/process/runner.go | 99 +-- .../agentctl/server/process/status_tracker.go | 36 +- .../server/process/status_tracker_test.go | 2 +- .../agentctl/server/shell/session_test.go | 1 - .../internal/agentctl/types/streams/doc.go | 1 - .../agentctl/types/streams/permission.go | 1 - .../internal/agentctl/types/streams/shell.go | 1 - .../agentctl/types/streams/tool_payload.go | 22 +- .../internal/clarification/handlers.go | 5 +- apps/backend/internal/clarification/store.go | 13 +- apps/backend/internal/clarification/types.go | 1 - apps/backend/internal/common/logger/logger.go | 1 - .../internal/common/portutil/portutil.go | 13 +- apps/backend/internal/debug/handlers.go | 4 +- .../internal/editors/service/service.go | 6 +- apps/backend/internal/events/bus/bus.go | 1 - apps/backend/internal/events/bus/memory.go | 14 +- apps/backend/internal/events/bus/nats.go | 1 - .../internal/events/bus/subscription.go | 1 - apps/backend/internal/events/types.go | 1 - .../internal/gateway/websocket/handler.go | 3 - .../backend/internal/gateway/websocket/hub.go | 2 +- .../websocket/session_notifications.go | 4 +- .../internal/gateway/websocket/setup.go | 1 - .../providers/system_provider.go | 2 +- .../internal/notifications/service/service.go | 8 +- .../orchestrator/event_handlers_streaming.go | 6 +- .../orchestrator/event_handlers_test.go | 3 +- .../orchestrator/executor/executor.go | 5 +- .../orchestrator/executor/executor_test.go | 16 +- .../orchestrator/handlers/queue_handlers.go | 12 +- .../handlers/queue_handlers_test.go | 8 +- .../orchestrator/messagequeue/types.go | 22 +- .../internal/orchestrator/queue/queue.go | 18 +- .../internal/orchestrator/queue/queue_test.go | 12 +- .../orchestrator/scheduler/scheduler_test.go | 12 +- apps/backend/internal/orchestrator/service.go | 23 +- .../internal/orchestrator/task_operations.go | 1 - .../orchestrator/watcher/watcher_test.go | 10 +- apps/backend/internal/task/dto/requests.go | 4 +- .../task/handlers/process_handlers.go | 1 - .../task/handlers/task_http_handlers.go | 2 +- .../task/handlers/workflow_handlers.go | 8 +- apps/backend/internal/task/models/git.go | 1 - apps/backend/internal/task/models/models.go | 6 +- .../internal/task/models/models_test.go | 24 +- .../internal/task/repository/sqlite/base.go | 1 - .../task/repository/sqlite/defaults.go | 1 - .../task/repository/sqlite/environment.go | 1 - .../task/repository/sqlite/executor.go | 1 - .../task/repository/sqlite/message.go | 1 - .../internal/task/repository/sqlite/plan.go | 1 - .../internal/task/repository/sqlite/task.go | 1 - .../task/repository/sqlite/task_repository.go | 2 - .../task/repository/sqlite/workspace.go | 1 - .../task/repository/task_repository_test.go | 18 +- .../internal/task/service/plan_service.go | 1 - apps/backend/internal/task/service/service.go | 2 +- .../internal/task/service/service_test.go | 10 +- .../internal/user/controller/controller.go | 18 +- apps/backend/internal/user/dto/dto.go | 62 +- apps/backend/internal/user/models/models.go | 24 +- apps/backend/internal/user/service/service.go | 36 +- apps/backend/internal/user/store/sqlite.go | 20 +- .../workflow/controller/controller.go | 16 +- .../internal/workflow/handlers/handlers.go | 3 +- .../internal/workflow/models/models.go | 2 +- .../internal/workflow/repository/sqlite.go | 2 - .../internal/workflow/service/service.go | 1 - apps/backend/internal/worktree/errors.go | 1 - apps/backend/pkg/acp/jsonrpc/types.go | 30 +- apps/backend/pkg/acp/protocol/types.go | 28 +- apps/backend/pkg/agent/protocol.go | 1 - apps/backend/pkg/amp/client.go | 18 +- apps/backend/pkg/api/v1/agent.go | 8 +- apps/backend/pkg/api/v1/user.go | 6 +- apps/backend/pkg/claudecode/types.go | 4 +- apps/backend/pkg/codex/types.go | 22 +- apps/backend/pkg/copilot/client.go | 44 +- apps/backend/pkg/opencode/types.go | 44 +- apps/backend/pkg/opencode/types_test.go | 4 +- apps/backend/pkg/websocket/actions.go | 134 +-- apps/cli/README.md | 19 +- apps/cli/README_internal.md | 62 +- apps/cli/src/dev.ts | 10 +- apps/cli/src/platform.ts | 7 +- apps/cli/src/shared.ts | 7 +- apps/cli/src/start.ts | 17 +- apps/cli/src/update.ts | 34 +- apps/cli/src/web.ts | 13 +- apps/package.json | 3 + apps/packages/theme/src/fonts.css | 63 +- apps/packages/theme/src/globals.css | 18 +- apps/packages/types/src/backend.ts | 86 +- apps/packages/types/src/http.ts | 20 +- apps/packages/types/src/index.ts | 4 +- apps/packages/ui/src/accordion.tsx | 39 +- apps/packages/ui/src/alert-dialog.tsx | 94 +-- apps/packages/ui/src/alert.tsx | 47 +- apps/packages/ui/src/aspect-ratio.tsx | 12 +- apps/packages/ui/src/avatar.tsx | 59 +- apps/packages/ui/src/badge.tsx | 27 +- apps/packages/ui/src/breadcrumb.tsx | 61 +- apps/packages/ui/src/button-group.tsx | 33 +- apps/packages/ui/src/button.tsx | 35 +- apps/packages/ui/src/calendar.tsx | 112 +-- apps/packages/ui/src/card.tsx | 51 +- apps/packages/ui/src/carousel.tsx | 157 ++-- apps/packages/ui/src/chart.tsx | 187 ++--- apps/packages/ui/src/checkbox.tsx | 24 +- apps/packages/ui/src/collapsible.tsx | 26 +- apps/packages/ui/src/command.tsx | 86 +- apps/packages/ui/src/context-menu.tsx | 111 ++- apps/packages/ui/src/dialog.tsx | 87 +- apps/packages/ui/src/drawer.tsx | 63 +- apps/packages/ui/src/dropdown-menu.tsx | 110 ++- apps/packages/ui/src/empty.tsx | 40 +- apps/packages/ui/src/field.tsx | 97 ++- apps/packages/ui/src/hooks/use-mobile.ts | 22 +- apps/packages/ui/src/hover-card.tsx | 28 +- apps/packages/ui/src/index.ts | 106 +-- apps/packages/ui/src/input-group.tsx | 64 +- apps/packages/ui/src/input-otp.tsx | 45 +- apps/packages/ui/src/input.tsx | 10 +- apps/packages/ui/src/item.tsx | 77 +- apps/packages/ui/src/kbd.tsx | 10 +- apps/packages/ui/src/label.tsx | 19 +- apps/packages/ui/src/lib/utils.ts | 4 +- apps/packages/ui/src/menubar.tsx | 115 ++- apps/packages/ui/src/navigation-menu.tsx | 63 +- apps/packages/ui/src/pagination.tsx | 76 +- apps/packages/ui/src/pannel-session.tsx | 44 +- apps/packages/ui/src/popover.tsx | 53 +- apps/packages/ui/src/progress.tsx | 14 +- apps/packages/ui/src/radio-group.tsx | 18 +- apps/packages/ui/src/resizable.tsx | 30 +- apps/packages/ui/src/scroll-area.tsx | 16 +- apps/packages/ui/src/scroll-on-overflow.tsx | 27 +- apps/packages/ui/src/select.tsx | 81 +- apps/packages/ui/src/separator.tsx | 14 +- apps/packages/ui/src/sheet.tsx | 68 +- apps/packages/ui/src/sidebar.tsx | 315 +++---- apps/packages/ui/src/skeleton.tsx | 6 +- apps/packages/ui/src/slider.tsx | 25 +- apps/packages/ui/src/sonner.tsx | 42 +- apps/packages/ui/src/spinner.tsx | 15 +- apps/packages/ui/src/switch.tsx | 16 +- apps/packages/ui/src/table.tsx | 54 +- apps/packages/ui/src/tabs.tsx | 44 +- apps/packages/ui/src/textarea.tsx | 10 +- apps/packages/ui/src/toggle-group.tsx | 41 +- apps/packages/ui/src/toggle.tsx | 21 +- apps/packages/ui/src/tooltip.tsx | 28 +- apps/packages/ui/src/utils.ts | 6 +- apps/pnpm-lock.yaml | 87 +- apps/prettier.config.mjs | 10 + apps/web/app/actions/agents.ts | 82 +- apps/web/app/actions/environments.ts | 23 +- apps/web/app/actions/executors.ts | 18 +- apps/web/app/actions/workspaces.ts | 225 +++-- apps/web/app/demo/agent-messages/page.tsx | 173 ++-- .../demo/messages/demo-messages-content.ts | 49 ++ .../app/demo/messages/demo-messages-data.ts | 615 +++++++------- apps/web/app/demo/messages/page.tsx | 14 +- apps/web/app/dockview-theme.css | 25 +- apps/web/app/fonts.css | 63 +- apps/web/app/globals.css | 100 ++- apps/web/app/layout.tsx | 32 +- apps/web/app/manifest.json | 2 +- apps/web/app/page-client.tsx | 20 +- apps/web/app/page.tsx | 96 ++- apps/web/app/s/[sessionId]/page.tsx | 170 ++-- apps/web/app/settings/agent/[id]/page.tsx | 14 +- .../agents/[agentId]/agent-save-helpers.ts | 78 +- .../agents/[agentId]/agent-setup-parts.tsx | 233 ++++++ .../app/settings/agents/[agentId]/page.tsx | 550 +++++++----- .../[agentId]/profile-mcp-config-card.tsx | 172 ++-- .../[profileId]/command-preview-card.tsx | 33 +- .../[agentId]/profiles/[profileId]/page.tsx | 21 +- .../[profileId]/use-agent-profile-settings.ts | 27 +- .../[agentId]/use-profile-mcp-config.ts | 63 +- apps/web/app/settings/agents/page.tsx | 110 ++- .../app/settings/environment/[id]/page.tsx | 118 ++- .../web/app/settings/environment/new/page.tsx | 193 +++-- apps/web/app/settings/environments/page.tsx | 16 +- apps/web/app/settings/executor/[id]/page.tsx | 318 ++++--- apps/web/app/settings/executor/new/page.tsx | 175 ++-- apps/web/app/settings/executors/page.tsx | 48 +- .../web/app/settings/general/editors/page.tsx | 10 +- .../settings/general/notifications/page.tsx | 8 +- apps/web/app/settings/general/page.tsx | 10 +- apps/web/app/settings/layout.tsx | 32 +- apps/web/app/settings/page.tsx | 4 +- apps/web/app/settings/prompts/page.tsx | 8 +- apps/web/app/settings/workspace/[id]/page.tsx | 2 +- .../workspace/[id]/repositories/page.tsx | 10 +- .../workspace/[id]/workflows/page.tsx | 12 +- apps/web/app/settings/workspace/page.tsx | 2 +- .../workspace/workspace-edit-client.tsx | 370 ++++++-- .../workspace/workspace-not-found-card.tsx | 19 + .../workspace-repositories-client.tsx | 649 +++++++++----- .../workspace-repositories-dialog.tsx | 158 ++++ .../workspace/workspace-workflows-client.tsx | 589 ++++++++----- .../workspace/workspace-workflows-dialogs.tsx | 201 +++++ .../workspace/workspaces-page-client.tsx | 55 +- apps/web/app/stats/loading.tsx | 4 +- apps/web/app/stats/page.tsx | 27 +- apps/web/app/stats/stats-charts.tsx | 140 ++-- apps/web/app/stats/stats-page-client.tsx | 312 +++++-- apps/web/app/stats/stats-sections.tsx | 121 +-- apps/web/app/tasks/columns.tsx | 148 +++- apps/web/app/tasks/page.tsx | 10 +- apps/web/app/tasks/tasks-page-client.tsx | 514 +++++++++--- apps/web/components/agent-logo.tsx | 28 +- apps/web/components/combobox.tsx | 84 +- apps/web/components/command-panel.tsx | 471 ++++++++--- apps/web/components/debug-overlay.tsx | 24 +- apps/web/components/diff-stat.tsx | 28 +- .../components/diff-worker-pool-provider.tsx | 34 +- apps/web/components/diff/comment-display.tsx | 32 +- apps/web/components/diff/comment-form.tsx | 23 +- .../components/diff/diff-header-toolbar.tsx | 35 +- apps/web/components/diff/diff-view-inline.tsx | 4 +- .../components/diff/diff-viewer-resolver.tsx | 33 +- apps/web/components/diff/diff-viewer.tsx | 100 ++- apps/web/components/diff/file-diff-viewer.tsx | 19 +- apps/web/components/diff/hunk-action-bar.tsx | 31 +- apps/web/components/diff/index.ts | 18 +- .../diff/use-diff-annotation-renderer.tsx | 42 +- apps/web/components/diff/use-diff-comments.ts | 56 +- apps/web/components/diff/use-diff-metadata.ts | 14 +- apps/web/components/diff/use-diff-options.tsx | 97 ++- .../components/diff/use-diff-viewer-state.ts | 274 ++++-- apps/web/components/diff/use-hunk-hover.ts | 88 +- .../codemirror/codemirror-code-block.tsx | 48 +- .../codemirror/codemirror-code-editor.tsx | 160 +++- .../codemirror/use-codemirror-editor-state.ts | 332 +++++--- .../editors/file-actions-dropdown.tsx | 49 +- .../components/editors/lsp-status-button.tsx | 36 +- .../monaco/diff-viewer-context-menu.tsx | 10 +- .../editors/monaco/diff-viewer-helpers.ts | 44 +- .../editors/monaco/diff-viewer-toolbar.tsx | 192 +++-- .../editors/monaco/monaco-code-block.tsx | 46 +- .../editors/monaco/monaco-code-editor.tsx | 169 ++-- .../editors/monaco/monaco-diff-viewer.tsx | 141 ++-- .../editors/monaco/monaco-editor-toolbar.tsx | 147 +++- .../components/editors/monaco/monaco-init.ts | 30 +- .../editors/monaco/monaco-inline-diff.tsx | 77 +- .../editors/monaco/monaco-loader.ts | 126 ++- .../editors/monaco/use-diff-view-zones.ts | 228 +++-- .../monaco/use-diff-viewer-comments.ts | 220 +++-- .../editors/monaco/use-global-folding.ts | 14 +- .../editors/monaco/use-monaco-editor-lsp.ts | 140 +++- .../editors/monaco/use-monaco-editor-state.ts | 276 ++++-- .../editors/pierre/pierre-diff-viewer.tsx | 4 +- .../editors/tiptap/comment-mark.tsx | 123 +-- .../editors/tiptap/plan-bubble-menu.tsx | 165 ++-- .../editors/tiptap/plan-drag-handle.tsx | 8 +- .../editors/tiptap/plan-slash-commands.ts | 117 ++- .../editors/tiptap/plan-slash-menu.tsx | 12 +- .../tiptap/tiptap-mermaid-extension.ts | 42 +- .../editors/tiptap/tiptap-plan-editor.tsx | 184 ++-- apps/web/components/empty-state-inline.tsx | 3 +- apps/web/components/global-commands.tsx | 125 ++- apps/web/components/grid-spinner.tsx | 4 +- apps/web/components/homepage-commands.tsx | 65 +- apps/web/components/kanban-board-grid.tsx | 67 +- apps/web/components/kanban-board.tsx | 245 +++--- apps/web/components/kanban-card.tsx | 114 ++- apps/web/components/kanban-column.tsx | 48 +- .../components/kanban-display-dropdown.tsx | 104 ++- apps/web/components/kanban-with-preview.tsx | 96 +-- .../components/kanban/graph2-connector.tsx | 21 +- .../components/kanban/graph2-step-node.tsx | 129 +-- .../kanban/graph2-task-pipeline.tsx | 55 +- .../kanban/kanban-header-mobile.tsx | 18 +- apps/web/components/kanban/kanban-header.tsx | 79 +- .../components/kanban/mobile-column-tabs.tsx | 26 +- .../components/kanban/mobile-drop-targets.tsx | 32 +- apps/web/components/kanban/mobile-fab.tsx | 18 +- .../components/kanban/mobile-menu-sheet.tsx | 132 +-- .../components/kanban/swimlane-container.tsx | 79 +- .../kanban/swimlane-graph-content.tsx | 239 ++++-- .../kanban/swimlane-graph2-content.tsx | 14 +- .../web/components/kanban/swimlane-header.tsx | 12 +- .../kanban/swimlane-kanban-content.tsx | 102 ++- .../components/kanban/swimlane-section.tsx | 6 +- .../components/kanban/swipeable-columns.tsx | 22 +- .../components/kanban/task-search-input.tsx | 20 +- .../components/keyboard-shortcut-tooltip.tsx | 19 +- apps/web/components/onboarding-dialog.tsx | 305 +++++-- apps/web/components/request-indicator.tsx | 12 +- apps/web/components/review/review-dialog.tsx | 187 +++-- .../components/review/review-diff-list.tsx | 274 ++++-- .../components/review/review-file-tree.tsx | 111 ++- apps/web/components/review/review-top-bar.tsx | 125 ++- apps/web/components/review/types.ts | 38 +- apps/web/components/session-commands.tsx | 247 ++++-- apps/web/components/session-tabs.tsx | 126 ++- .../settings/add-tui-agent-dialog.tsx | 129 ++- apps/web/components/settings/agent-card.tsx | 12 +- .../settings/agent-profile-page.tsx | 178 ++-- .../web/components/settings/editable-card.tsx | 22 +- apps/web/components/settings/editor-form.tsx | 176 ++-- .../settings/editors-settings-state.tsx | 372 +++++++++ .../components/settings/editors-settings.tsx | 613 +++++++------- .../components/settings/environment-card.tsx | 20 +- .../components/settings/general-settings.tsx | 46 +- .../components/settings/key-value-input.tsx | 40 +- .../components/settings/model-combobox.tsx | 153 +++- .../notifications-settings-actions.ts | 354 ++++++++ .../settings/notifications-settings.tsx | 547 +++++------- .../settings/profile-form-fields.tsx | 40 +- .../components/settings/prompts-settings.tsx | 180 +++- .../components/settings/repository-card.tsx | 161 ++-- .../settings/settings-app-sidebar.tsx | 66 +- .../settings/settings-layout-client.tsx | 29 +- .../settings/settings-page-template.tsx | 18 +- .../components/settings/settings-section.tsx | 14 +- .../settings/shell-settings-card.tsx | 56 +- .../components/settings/unsaved-indicator.tsx | 22 +- .../settings/workflow-card-actions.ts | 429 ++++++++++ .../web/components/settings/workflow-card.tsx | 497 ++++++----- .../settings/workflow-export-dialog.tsx | 39 +- .../workflow-pipeline-editor-helpers.tsx | 129 ++- .../workflow-pipeline-editor-panels.tsx | 615 +++++++------- .../workflow-pipeline-editor-step-actions.tsx | 254 ++++++ .../settings/workflow-pipeline-editor.tsx | 131 ++- apps/web/components/state-hydrator.tsx | 8 +- apps/web/components/state-provider.tsx | 16 +- apps/web/components/step-capability-icons.tsx | 47 +- .../components/task-create-dialog-footer.tsx | 185 ++-- .../task-create-dialog-form-body.tsx | 128 ++- .../components/task-create-dialog-options.tsx | 50 +- .../task-create-dialog-selectors.tsx | 48 +- .../components/task-create-dialog-state.ts | 542 ++++++++++++ .../components/task-create-dialog-submit.tsx | 471 ++++++++--- apps/web/components/task-create-dialog.tsx | 590 +++++-------- apps/web/components/task-preview-panel.tsx | 18 +- apps/web/components/task/browser-panel.tsx | 48 +- .../components/task/changes-panel-dialogs.tsx | 64 +- .../task/changes-panel-file-row.tsx | 24 +- .../components/task/changes-panel-header.tsx | 170 ++++ .../task/changes-panel-timeline.tsx | 73 +- apps/web/components/task/changes-panel.tsx | 607 ++++++++------ .../web/components/task/chat-context-items.ts | 181 ++++ .../components/task/chat/chat-input-body.tsx | 249 ++++++ .../task/chat/chat-input-container.tsx | 462 ++++------ .../task/chat/chat-input-focus-hint.tsx | 18 +- .../task/chat/chat-input-toolbar.tsx | 73 +- .../task/chat/clarification-input-overlay.tsx | 177 ++-- .../task/chat/context-items/comment-item.tsx | 12 +- .../task/chat/context-items/context-chip.tsx | 34 +- .../context-items/context-item-renderer.tsx | 28 +- .../task/chat/context-items/context-zone.tsx | 8 +- .../task/chat/context-items/file-item.tsx | 10 +- .../task/chat/context-items/image-item.tsx | 14 +- .../task/chat/context-items/index.ts | 20 +- .../chat/context-items/lazy-file-preview.tsx | 14 +- .../chat/context-items/lazy-plan-preview.tsx | 30 +- .../chat/context-items/plan-comment-item.tsx | 14 +- .../task/chat/context-items/plan-item.tsx | 10 +- .../task/chat/context-items/prompt-item.tsx | 10 +- .../chat/context-items/prompt-preview.tsx | 6 +- .../components/task/chat/context-popover.tsx | 220 +++-- .../components/task/chat/editor-context.tsx | 4 +- .../task/chat/image-attachment-preview.tsx | 51 +- .../web/components/task/chat/mention-menu.tsx | 22 +- .../components/task/chat/message-renderer.tsx | 132 ++- .../task/chat/messages/agent-status.tsx | 86 +- .../task/chat/messages/chat-message.tsx | 180 ++-- .../clarification-request-message.tsx | 20 +- .../task/chat/messages/code-block.tsx | 18 +- .../task/chat/messages/diff-view-block.tsx | 23 +- .../task/chat/messages/expandable-row.tsx | 16 +- .../task/chat/messages/file-path-button.tsx | 52 +- .../task/chat/messages/inline-code.tsx | 28 +- .../task/chat/messages/message-actions.tsx | 130 ++- .../chat/messages/permission-action-row.tsx | 10 +- .../messages/permission-request-message.tsx | 59 +- .../messages/review-comments-attachment.tsx | 60 +- .../task/chat/messages/rich-blocks.tsx | 66 +- .../messages/script-execution-message.tsx | 144 +++- .../task/chat/messages/status-message.tsx | 156 +++- .../task/chat/messages/thinking-message.tsx | 56 +- .../task/chat/messages/todo-message.tsx | 22 +- .../task/chat/messages/tool-call-message.tsx | 182 ++-- .../task/chat/messages/tool-edit-message.tsx | 114 ++- .../chat/messages/tool-execute-message.tsx | 70 +- .../task/chat/messages/tool-read-message.tsx | 48 +- .../chat/messages/tool-search-message.tsx | 62 +- .../chat/messages/tool-subagent-message.tsx | 53 +- .../task/chat/messages/turn-group-message.tsx | 81 +- .../task/chat/messages/use-expand-state.ts | 2 +- apps/web/components/task/chat/popup-menu.tsx | 38 +- .../task/chat/queued-message-indicator.tsx | 220 +++-- .../components/task/chat/resize-handle.tsx | 12 +- .../components/task/chat/rich-text-input.tsx | 144 ++-- .../task/chat/slash-command-menu.tsx | 8 +- .../task/chat/tiptap-code-block-view.tsx | 42 +- .../components/task/chat/tiptap-helpers.ts | 106 +-- .../web/components/task/chat/tiptap-input.tsx | 462 +++++----- .../task/chat/tiptap-mention-extension.tsx | 80 +- .../task/chat/tiptap-suggestion.tsx | 59 +- .../web/components/task/chat/todo-summary.tsx | 8 +- .../task/chat/token-usage-display.tsx | 41 +- apps/web/components/task/chat/types.ts | 10 +- .../task/chat/use-chat-input-container.ts | 152 ++++ .../task/chat/use-chat-input-state.ts | 178 ++-- .../components/task/chat/use-tiptap-editor.ts | 203 ++--- .../task/chat/virtualized-message-list.tsx | 249 ++++-- .../components/task/comment-view-popover.tsx | 99 ++- .../components/task/commit-detail-panel.tsx | 53 +- .../task/dockview-desktop-layout.tsx | 216 ++--- .../task/dockview-header-actions.tsx | 166 ++-- .../components/task/dockview-watermark.tsx | 46 +- .../task/document/document-controls.tsx | 19 +- .../task/document/document-panel.tsx | 83 +- .../task/editor-comment-popover.tsx | 138 ++- apps/web/components/task/editors-menu.tsx | 38 +- .../components/task/file-binary-viewer.tsx | 6 +- .../task/file-browser-load-state.tsx | 59 ++ .../components/task/file-browser-parts.tsx | 418 ++++----- .../task/file-browser-search-header.tsx | 48 ++ apps/web/components/task/file-browser.tsx | 328 ++++---- .../components/task/file-editor-content.tsx | 20 +- .../web/components/task/file-editor-panel.tsx | 155 ++-- .../web/components/task/file-image-viewer.tsx | 6 +- apps/web/components/task/file-status-icon.tsx | 18 +- .../components/task/file-viewer-content.tsx | 18 +- apps/web/components/task/files-panel.tsx | 46 +- .../web/components/task/inline-file-input.tsx | 21 +- .../task/layout-preset-selector.tsx | 101 +-- apps/web/components/task/mobile/index.ts | 10 +- .../task/mobile/session-mobile-bottom-nav.tsx | 97 ++- .../task/mobile/session-mobile-layout.tsx | 125 ++- .../session-mobile-top-bar-dialog-parts.tsx | 86 ++ .../task/mobile/session-mobile-top-bar.tsx | 468 ++++++++--- .../task/mobile/session-tablet-layout.tsx | 78 +- .../mobile/session-task-switcher-sheet.tsx | 385 ++++++--- apps/web/components/task/model-selector.tsx | 66 +- apps/web/components/task/panel-primitives.tsx | 64 +- .../components/task/passthrough-terminal.tsx | 394 ++++++--- .../task/plan-selection-popover.tsx | 142 ++-- .../task/preview/preview-controller.tsx | 4 +- .../task/preview/preview-controls.tsx | 88 +- .../components/task/preview/preview-panel.tsx | 309 +++++-- .../task/session-workflow-progress.tsx | 23 +- .../web/components/task/sessions-dropdown.tsx | 200 ++--- apps/web/components/task/shell-terminal.tsx | 217 +++-- apps/web/components/task/sidebar-button.tsx | 32 +- .../components/task/task-archived-context.tsx | 12 +- .../task/task-center-panel-restoration.ts | 239 ++++++ .../web/components/task/task-center-panel.tsx | 469 ++++++----- .../components/task/task-changes-panel.tsx | 456 +++++++--- apps/web/components/task/task-chat-panel.tsx | 707 ++++++++-------- .../components/task/task-files-panel-hooks.ts | 354 ++++++++ .../task/task-files-panel-parts.tsx | 519 ++++++++++++ apps/web/components/task/task-files-panel.tsx | 579 ++----------- apps/web/components/task/task-item-menu.tsx | 30 +- apps/web/components/task/task-item.tsx | 51 +- apps/web/components/task/task-layout.tsx | 22 +- .../web/components/task/task-page-content.tsx | 356 +++++--- apps/web/components/task/task-plan-panel.tsx | 208 +++-- apps/web/components/task/task-right-panel.tsx | 343 +++++--- .../components/task/task-session-sidebar.tsx | 265 ++++-- .../components/task/task-state-actions.tsx | 12 +- apps/web/components/task/task-switcher.tsx | 22 +- apps/web/components/task/task-top-bar.tsx | 97 ++- apps/web/components/task/terminal-panel.tsx | 41 +- apps/web/components/task/workflow-stepper.tsx | 77 +- .../web/components/task/workflow-switcher.tsx | 32 +- .../components/task/workspace-switcher.tsx | 30 +- apps/web/components/theme-provider.tsx | 12 +- apps/web/components/theme-toggle.tsx | 20 +- apps/web/components/toast-provider.tsx | 91 +- .../components/ui/data-table-pagination.tsx | 142 ++-- apps/web/components/ui/data-table.tsx | 62 +- apps/web/components/ui/file-icon.tsx | 5 +- apps/web/components/vcs-split-button.tsx | 156 ++-- apps/web/components/vcs/vcs-dialogs.tsx | 327 ++++++-- apps/web/components/workflow-selector-row.tsx | 28 +- apps/web/components/ws-connector.tsx | 12 +- apps/web/eslint.config.mjs | 2 +- .../domains/comments/use-diff-comments.ts | 8 +- .../domains/comments/use-pending-comments.ts | 8 +- .../domains/comments/use-plan-comments.ts | 23 +- apps/web/hooks/domains/kanban/index.ts | 6 +- .../kanban/use-all-workflow-snapshots.ts | 31 +- .../domains/kanban/use-kanban-actions.ts | 38 +- .../hooks/domains/kanban/use-kanban-data.ts | 40 +- .../domains/kanban/use-kanban-navigation.ts | 33 +- .../domains/kanban/use-swimlane-collapse.ts | 6 +- .../hooks/domains/kanban/use-swimlane-move.ts | 58 +- .../domains/session/use-cumulative-diff.ts | 24 +- apps/web/hooks/domains/session/use-queue.ts | 24 +- .../domains/session/use-session-agent.ts | 61 +- .../domains/session/use-session-agentctl.ts | 20 +- .../domains/session/use-session-commits.ts | 24 +- .../session/use-session-context-window.ts | 35 +- .../session/use-session-git-snapshots.ts | 23 +- .../domains/session/use-session-git-status.ts | 119 +-- .../domains/session/use-session-messages.ts | 64 +- .../domains/session/use-session-model.ts | 10 +- .../domains/session/use-session-resumption.ts | 124 ++- .../domains/session/use-session-state.ts | 14 +- .../hooks/domains/session/use-session-turn.ts | 19 +- .../domains/session/use-session-worktrees.ts | 8 +- apps/web/hooks/domains/session/use-session.ts | 20 +- .../hooks/domains/session/use-task-plan.ts | 37 +- .../hooks/domains/session/use-terminals.ts | 271 ++++-- .../hooks/domains/session/use-user-shells.ts | 46 +- .../domains/settings/use-available-agents.ts | 8 +- .../domains/settings/use-custom-prompts.ts | 10 +- .../domains/settings/use-dynamic-models.ts | 12 +- .../web/hooks/domains/settings/use-editors.ts | 30 +- .../settings/use-notification-providers.ts | 19 +- .../domains/settings/use-settings-data.ts | 26 +- .../domains/settings/use-shell-settings.ts | 4 +- .../domains/settings/use-workflow-settings.ts | 31 +- .../domains/workspace/use-repositories.ts | 18 +- .../workspace/use-repository-branches.ts | 18 +- .../workspace/use-repository-scripts.ts | 20 +- .../hooks/domains/workspace/use-repository.ts | 6 +- apps/web/hooks/use-capture-keydown.ts | 12 +- apps/web/hooks/use-copy-to-clipboard.ts | 23 +- apps/web/hooks/use-debounce.ts | 6 +- apps/web/hooks/use-diff-editor-height.ts | 9 +- apps/web/hooks/use-drag-and-drop.ts | 157 ++-- apps/web/hooks/use-editor-keybinds.ts | 42 +- apps/web/hooks/use-editor-resolver.ts | 2 +- .../hooks/use-editor-view-zone-comments.ts | 18 +- apps/web/hooks/use-file-editors.ts | 373 ++++++--- apps/web/hooks/use-file-operations.ts | 90 +- apps/web/hooks/use-git-operations.ts | 187 ++--- apps/web/hooks/use-git-with-feedback.ts | 23 +- apps/web/hooks/use-global-view-mode.ts | 18 +- apps/web/hooks/use-gutter-comments.ts | 231 ++--- apps/web/hooks/use-inline-mention.ts | 199 +++-- apps/web/hooks/use-inline-slash.ts | 117 ++- apps/web/hooks/use-kanban-display-settings.ts | 45 +- apps/web/hooks/use-kanban-layout.ts | 6 +- apps/web/hooks/use-keyboard-shortcut.ts | 29 +- apps/web/hooks/use-lazy-load-messages.ts | 16 +- apps/web/hooks/use-lsp-file-opener.ts | 18 +- apps/web/hooks/use-lsp.ts | 28 +- apps/web/hooks/use-message-handler.ts | 104 ++- apps/web/hooks/use-message-navigation.ts | 14 +- apps/web/hooks/use-mobile.ts | 22 +- apps/web/hooks/use-open-session-folder.ts | 8 +- apps/web/hooks/use-open-session-in-editor.ts | 10 +- apps/web/hooks/use-panel-actions.ts | 32 +- apps/web/hooks/use-preview-panel.ts | 443 ++++++---- apps/web/hooks/use-processed-messages.ts | 125 ++- apps/web/hooks/use-register-commands.ts | 8 +- apps/web/hooks/use-resizable-input.ts | 44 +- apps/web/hooks/use-responsive-breakpoint.ts | 28 +- apps/web/hooks/use-session-file-reviews.ts | 76 +- apps/web/hooks/use-session-layout-state.ts | 106 ++- apps/web/hooks/use-task-actions.ts | 4 +- apps/web/hooks/use-task-chat-session.ts | 10 +- apps/web/hooks/use-task-crud.ts | 20 +- apps/web/hooks/use-task-removal.ts | 44 +- apps/web/hooks/use-task-repositories.ts | 6 +- apps/web/hooks/use-task-session.ts | 14 +- apps/web/hooks/use-task-sessions.ts | 58 +- apps/web/hooks/use-task.ts | 13 +- apps/web/hooks/use-tasks.ts | 6 +- apps/web/hooks/use-user-display-settings.ts | 123 ++- apps/web/hooks/use-workflow-snapshot.ts | 10 +- apps/web/hooks/use-workflows.ts | 8 +- apps/web/hooks/use-worktree.ts | 6 +- apps/web/lib/agent-permissions.test.ts | 47 +- apps/web/lib/agent-permissions.ts | 16 +- apps/web/lib/api/client.ts | 6 +- apps/web/lib/api/domains/debug-api.ts | 16 +- apps/web/lib/api/domains/kanban-api.ts | 40 +- apps/web/lib/api/domains/plan-api.ts | 25 +- apps/web/lib/api/domains/process-api.ts | 27 +- apps/web/lib/api/domains/queue-api.ts | 16 +- apps/web/lib/api/domains/session-api.ts | 32 +- apps/web/lib/api/domains/settings-api.ts | 103 +-- apps/web/lib/api/domains/stats-api.ts | 10 +- apps/web/lib/api/domains/user-shell-api.ts | 21 +- apps/web/lib/api/domains/workflow-api.ts | 27 +- apps/web/lib/api/domains/workspace-api.ts | 28 +- apps/web/lib/api/index.ts | 14 +- apps/web/lib/commands/command-registry.tsx | 12 +- apps/web/lib/commands/types.ts | 6 +- apps/web/lib/config.ts | 22 +- apps/web/lib/diff/adapter.ts | 77 +- apps/web/lib/diff/comment-utils.ts | 19 +- apps/web/lib/diff/index.ts | 4 +- apps/web/lib/diff/types.ts | 10 +- apps/web/lib/editor/language-map.ts | 212 ++--- apps/web/lib/executor-icons.ts | 10 +- apps/web/lib/http/use-request.ts | 26 +- apps/web/lib/kanban/filters.ts | 10 +- apps/web/lib/kanban/view-registry.ts | 29 +- apps/web/lib/keyboard/constants.test.ts | 130 +-- apps/web/lib/keyboard/constants.ts | 105 ++- apps/web/lib/keyboard/utils.test.ts | 234 +++--- apps/web/lib/keyboard/utils.ts | 73 +- apps/web/lib/languages.ts | 142 ++-- apps/web/lib/layout/dockview-theme.ts | 2 +- apps/web/lib/layout/read-layout-defaults.ts | 21 +- apps/web/lib/layout/use-default-layout.ts | 29 +- apps/web/lib/links.ts | 2 +- apps/web/lib/local-storage.ts | 125 +-- apps/web/lib/lsp/lsp-client-manager.ts | 520 ++++-------- apps/web/lib/lsp/lsp-json-rpc.ts | 293 +++++++ apps/web/lib/lsp/lsp-providers.ts | 135 ++- apps/web/lib/notifications/events.ts | 7 +- apps/web/lib/preview-url-detector.test.ts | 180 ++-- apps/web/lib/preview-url-detector.ts | 10 +- apps/web/lib/settings/constants.ts | 12 +- apps/web/lib/settings/types.ts | 14 +- apps/web/lib/ssr/mapper.ts | 15 +- apps/web/lib/state/context-files-store.ts | 11 +- .../web/lib/state/dockview-layout-builders.ts | 47 +- apps/web/lib/state/dockview-store.ts | 790 ++++++++++-------- apps/web/lib/state/editor-resolver-store.ts | 48 +- apps/web/lib/state/hydration/hydrator.ts | 96 ++- .../lib/state/hydration/merge-strategies.ts | 17 +- apps/web/lib/state/layout-manager/applier.ts | 34 +- .../web/lib/state/layout-manager/constants.ts | 50 +- apps/web/lib/state/layout-manager/index.ts | 42 +- apps/web/lib/state/layout-manager/presets.ts | 52 +- .../lib/state/layout-manager/serializer.ts | 95 ++- apps/web/lib/state/layout-manager/sizing.ts | 10 +- apps/web/lib/state/layout-manager/types.ts | 4 +- apps/web/lib/state/layout-store.ts | 81 +- .../state/slices/comments/comments-store.ts | 43 +- apps/web/lib/state/slices/comments/format.ts | 31 +- apps/web/lib/state/slices/comments/index.ts | 8 +- .../lib/state/slices/comments/persistence.ts | 6 +- apps/web/lib/state/slices/comments/types.ts | 16 +- apps/web/lib/state/slices/index.ts | 53 +- .../lib/state/slices/kanban/kanban-slice.ts | 6 +- apps/web/lib/state/slices/kanban/types.ts | 12 +- .../session-runtime/session-runtime-slice.ts | 122 ++- .../lib/state/slices/session-runtime/types.ts | 17 +- .../lib/state/slices/session/session-slice.ts | 110 ++- apps/web/lib/state/slices/session/types.ts | 10 +- .../state/slices/settings/settings-slice.ts | 8 +- apps/web/lib/state/slices/settings/types.ts | 24 +- apps/web/lib/state/slices/ui/types.ts | 18 +- apps/web/lib/state/slices/ui/ui-slice.ts | 12 +- apps/web/lib/state/slices/workspace/types.ts | 4 +- .../state/slices/workspace/workspace-slice.ts | 18 +- apps/web/lib/state/store.ts | 196 +++-- apps/web/lib/theme/colors.ts | 60 +- apps/web/lib/theme/editor-theme.ts | 134 +-- apps/web/lib/theme/terminal-theme.ts | 44 +- apps/web/lib/types/backend.ts | 275 +++--- apps/web/lib/types/context.ts | 18 +- apps/web/lib/types/git-events.ts | 10 +- apps/web/lib/types/http-agents.ts | 10 +- apps/web/lib/types/http.ts | 105 +-- apps/web/lib/ui/state-icons.tsx | 34 +- apps/web/lib/utils.test.ts | 102 ++- apps/web/lib/utils.ts | 263 +++--- apps/web/lib/utils/file-diff.ts | 31 +- apps/web/lib/utils/file-path.ts | 8 +- apps/web/lib/utils/file-types.ts | 93 ++- apps/web/lib/utils/needs-action.ts | 10 +- apps/web/lib/ws/client.ts | 117 +-- apps/web/lib/ws/connection.ts | 2 +- apps/web/lib/ws/handlers/agent-session.ts | 89 +- apps/web/lib/ws/handlers/agents.ts | 99 ++- .../web/lib/ws/handlers/available-commands.ts | 10 +- apps/web/lib/ws/handlers/diffs.ts | 8 +- apps/web/lib/ws/handlers/environments.ts | 21 +- apps/web/lib/ws/handlers/executors.ts | 16 +- apps/web/lib/ws/handlers/git-status.ts | 27 +- apps/web/lib/ws/handlers/kanban.ts | 16 +- apps/web/lib/ws/handlers/messages.ts | 16 +- apps/web/lib/ws/handlers/notifications.ts | 16 +- apps/web/lib/ws/handlers/system-events.ts | 8 +- apps/web/lib/ws/handlers/task-plans.ts | 17 +- apps/web/lib/ws/handlers/tasks.ts | 39 +- apps/web/lib/ws/handlers/terminals.ts | 22 +- apps/web/lib/ws/handlers/turns.ts | 27 +- apps/web/lib/ws/handlers/types.ts | 2 +- apps/web/lib/ws/handlers/users.ts | 10 +- apps/web/lib/ws/handlers/workflows.ts | 18 +- apps/web/lib/ws/handlers/workspaces.ts | 26 +- apps/web/lib/ws/router.ts | 40 +- apps/web/lib/ws/use-websocket.tsx | 40 +- apps/web/lib/ws/utils.ts | 4 +- apps/web/lib/ws/workspace-files.ts | 35 +- apps/web/package.json | 3 +- apps/web/tailwind.config.ts | 8 +- apps/web/vitest.config.ts | 4 +- 753 files changed, 35129 insertions(+), 21169 deletions(-) create mode 100644 apps/.prettierignore create mode 100644 apps/prettier.config.mjs create mode 100644 apps/web/app/demo/messages/demo-messages-content.ts create mode 100644 apps/web/app/settings/agents/[agentId]/agent-setup-parts.tsx create mode 100644 apps/web/app/settings/workspace/workspace-not-found-card.tsx create mode 100644 apps/web/app/settings/workspace/workspace-repositories-dialog.tsx create mode 100644 apps/web/app/settings/workspace/workspace-workflows-dialogs.tsx create mode 100644 apps/web/components/settings/editors-settings-state.tsx create mode 100644 apps/web/components/settings/notifications-settings-actions.ts create mode 100644 apps/web/components/settings/workflow-card-actions.ts create mode 100644 apps/web/components/settings/workflow-pipeline-editor-step-actions.tsx create mode 100644 apps/web/components/task-create-dialog-state.ts create mode 100644 apps/web/components/task/changes-panel-header.tsx create mode 100644 apps/web/components/task/chat-context-items.ts create mode 100644 apps/web/components/task/chat/chat-input-body.tsx create mode 100644 apps/web/components/task/chat/use-chat-input-container.ts create mode 100644 apps/web/components/task/file-browser-load-state.tsx create mode 100644 apps/web/components/task/file-browser-search-header.tsx create mode 100644 apps/web/components/task/mobile/session-mobile-top-bar-dialog-parts.tsx create mode 100644 apps/web/components/task/task-center-panel-restoration.ts create mode 100644 apps/web/components/task/task-files-panel-hooks.ts create mode 100644 apps/web/components/task/task-files-panel-parts.tsx create mode 100644 apps/web/lib/lsp/lsp-json-rpc.ts diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml index 33c6fa6be2..4da24f95be 100644 --- a/.github/workflows/backend-tests.yml +++ b/.github/workflows/backend-tests.yml @@ -45,6 +45,39 @@ jobs: - name: Build run: go build -v ./cmd/kandev + - name: Check gofmt + shell: bash + run: | + set -euo pipefail + + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + BASE_SHA="${{ github.event.pull_request.base.sha }}" + else + BASE_SHA="${{ github.event.before }}" + fi + + if [[ -z "${BASE_SHA}" || "${BASE_SHA}" == "0000000000000000000000000000000000000000" ]]; then + BASE_SHA="$(git rev-list --max-parents=0 HEAD)" + fi + + CHANGED_GO_FILES="$( + git diff --name-only --diff-filter=ACMRT "${BASE_SHA}"..."${{ github.sha }}" -- apps/backend \ + | grep -E '^apps/backend/.*\.go$' \ + || true + )" + + if [[ -z "${CHANGED_GO_FILES}" ]]; then + echo "No backend Go files changed." + exit 0 + fi + + UNFORMATTED="$(echo "${CHANGED_GO_FILES}" | sed 's#^apps/backend/##' | xargs gofmt -l)" + if [[ -n "${UNFORMATTED}" ]]; then + echo "The following changed Go files are not formatted with gofmt:" + echo "${UNFORMATTED}" + exit 1 + fi + - name: Run golangci-lint uses: golangci/golangci-lint-action@v9 with: diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml index 673b393630..144fc8b610 100644 --- a/.github/workflows/frontend-tests.yml +++ b/.github/workflows/frontend-tests.yml @@ -4,6 +4,10 @@ on: push: branches: [main] paths: + - "apps/cli/**" + - "apps/package.json" + - "apps/prettier.config.mjs" + - "apps/.prettierignore" - "apps/web/**" - "apps/packages/**" - "apps/pnpm-lock.yaml" @@ -11,6 +15,10 @@ on: pull_request: branches: [main] paths: + - "apps/cli/**" + - "apps/package.json" + - "apps/prettier.config.mjs" + - "apps/.prettierignore" - "apps/web/**" - "apps/packages/**" - "apps/pnpm-lock.yaml" @@ -41,6 +49,38 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Check formatting + shell: bash + run: | + set -euo pipefail + + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + BASE_SHA="${{ github.event.pull_request.base.sha }}" + else + BASE_SHA="${{ github.event.before }}" + fi + + if [[ -z "${BASE_SHA}" || "${BASE_SHA}" == "0000000000000000000000000000000000000000" ]]; then + BASE_SHA="$(git rev-list --max-parents=0 HEAD)" + fi + + CHANGED_FILES="$( + git diff --name-only --diff-filter=ACMRT "${BASE_SHA}"..."${{ github.sha }}" \ + | grep -E '^apps/(web|cli|packages)/.*\.(ts|tsx|js|jsx|mjs|cjs|json|md|mdx|yml|yaml|css|scss)$' \ + || true + )" + + if [[ -z "${CHANGED_FILES}" ]]; then + echo "No Prettier-scoped files changed." + exit 0 + fi + + echo "Checking Prettier on changed files:" + echo "${CHANGED_FILES}" + echo "${CHANGED_FILES}" \ + | sed 's#^apps/##' \ + | xargs pnpm --dir apps exec prettier --check --ignore-unknown + - name: Run lint run: pnpm --filter @kandev/web lint diff --git a/.gitignore b/.gitignore index 7c06cb9721..dfed567b82 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ apps/backend/mock-agent .next/ out/ node_modules/ +.pnpm-store/ # TypeScript *.tsbuildinfo diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 366bfb0b53..bff409c4be 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,6 +2,13 @@ repos: # Backend (Go) hooks - repo: local hooks: + - id: gofmt + name: gofmt (backend) + entry: bash -c 'gofmt -w "$@"' -- + language: system + files: ^apps/backend/.*\.go$ + pass_filenames: true + - id: go-tests name: Go tests (backend) entry: bash -c 'cd apps/backend && go test ./...' @@ -19,6 +26,13 @@ repos: # Web app (TypeScript/React) hooks - repo: local hooks: + - id: prettier-format + name: Prettier format (web/cli/packages) + entry: bash -c 'cd apps && pnpm exec prettier --write --ignore-unknown "${@/#apps\//}"' -- + language: system + files: ^apps/(web|cli|packages)/.*\.(ts|tsx|js|jsx|mjs|cjs|json|md|mdx|yml|yaml|css|scss)$ + pass_filenames: true + - id: web-lint name: Web lint entry: bash -c 'cd apps && pnpm --filter @kandev/web lint' diff --git a/Makefile b/Makefile index 95e2a38f10..87fec7b7b7 100644 --- a/Makefile +++ b/Makefile @@ -82,9 +82,10 @@ help: @echo " lint Run linters for both components" @echo " lint-backend Run Go linters" @echo " lint-web Run ESLint" + @echo " lint-format Check formatting with Prettier (web/cli/packages)" @echo " fmt Format all code" @echo " fmt-backend Format Go code" - @echo " fmt-web Format web code with ESLint" + @echo " fmt-web Format web/cli/packages with Prettier, then ESLint --fix (web)" @echo "" @echo "Cleanup:" @echo " clean Remove all build artifacts" @@ -220,6 +221,11 @@ lint-web: @printf "$(CYAN)Linting web app...$(RESET)\n" @cd $(APPS_DIR) && $(PNPM) --filter @kandev/web lint +.PHONY: lint-format +lint-format: + @printf "$(CYAN)Checking formatting...$(RESET)\n" + @cd $(APPS_DIR) && $(PNPM) run format:check + .PHONY: fmt fmt: fmt-backend fmt-web @printf "\n$(GREEN)$(BOLD)✓ Code formatting complete!$(RESET)\n" @@ -232,7 +238,7 @@ fmt-backend: .PHONY: fmt-web fmt-web: @printf "$(CYAN)Formatting web code...$(RESET)\n" - @cd $(APPS_DIR) && $(PNPM) --filter @kandev/web lint -- --fix || true + @cd $(APPS_DIR) && $(PNPM) run format .PHONY: typecheck-web typecheck-web: diff --git a/apps/.prettierignore b/apps/.prettierignore new file mode 100644 index 0000000000..69e7bafa8f --- /dev/null +++ b/apps/.prettierignore @@ -0,0 +1,5 @@ +node_modules +.next +dist +build +coverage diff --git a/apps/backend/cmd/kandev/gateway.go b/apps/backend/cmd/kandev/gateway.go index 46d775926d..4746fb8291 100644 --- a/apps/backend/cmd/kandev/gateway.go +++ b/apps/backend/cmd/kandev/gateway.go @@ -12,9 +12,9 @@ import ( "github.com/kandev/kandev/internal/common/logger" "github.com/kandev/kandev/internal/common/scripts" "github.com/kandev/kandev/internal/events" - lspinstaller "github.com/kandev/kandev/internal/lsp/installer" "github.com/kandev/kandev/internal/events/bus" gateways "github.com/kandev/kandev/internal/gateway/websocket" + lspinstaller "github.com/kandev/kandev/internal/lsp/installer" notificationcontroller "github.com/kandev/kandev/internal/notifications/controller" notificationservice "github.com/kandev/kandev/internal/notifications/service" notificationstore "github.com/kandev/kandev/internal/notifications/store" diff --git a/apps/backend/cmd/kandev/helpers.go b/apps/backend/cmd/kandev/helpers.go index 48e69c0a64..8cc48096a1 100644 --- a/apps/backend/cmd/kandev/helpers.go +++ b/apps/backend/cmd/kandev/helpers.go @@ -9,12 +9,12 @@ import ( "go.uber.org/zap" "github.com/kandev/kandev/internal/agent/docker" - "github.com/kandev/kandev/internal/agent/lifecycle" agenthandlers "github.com/kandev/kandev/internal/agent/handlers" + "github.com/kandev/kandev/internal/agent/lifecycle" agentsettingscontroller "github.com/kandev/kandev/internal/agent/settings/controller" agentsettingshandlers "github.com/kandev/kandev/internal/agent/settings/handlers" - analyticsrepository "github.com/kandev/kandev/internal/analytics/repository" analyticshandlers "github.com/kandev/kandev/internal/analytics/handlers" + analyticsrepository "github.com/kandev/kandev/internal/analytics/repository" "github.com/kandev/kandev/internal/clarification" "github.com/kandev/kandev/internal/common/config" "github.com/kandev/kandev/internal/common/logger" @@ -29,9 +29,9 @@ import ( "github.com/kandev/kandev/internal/orchestrator" promptcontroller "github.com/kandev/kandev/internal/prompts/controller" prompthandlers "github.com/kandev/kandev/internal/prompts/handlers" + taskhandlers "github.com/kandev/kandev/internal/task/handlers" "github.com/kandev/kandev/internal/task/models" "github.com/kandev/kandev/internal/task/repository" - taskhandlers "github.com/kandev/kandev/internal/task/handlers" taskservice "github.com/kandev/kandev/internal/task/service" usercontroller "github.com/kandev/kandev/internal/user/controller" userhandlers "github.com/kandev/kandev/internal/user/handlers" diff --git a/apps/backend/cmd/kandev/worktree.go b/apps/backend/cmd/kandev/worktree.go index b9d0a5118c..d3d1507089 100644 --- a/apps/backend/cmd/kandev/worktree.go +++ b/apps/backend/cmd/kandev/worktree.go @@ -5,9 +5,9 @@ import ( "github.com/kandev/kandev/internal/agent/lifecycle" "github.com/kandev/kandev/internal/common/config" - "github.com/kandev/kandev/internal/db" "github.com/kandev/kandev/internal/common/constants" "github.com/kandev/kandev/internal/common/logger" + "github.com/kandev/kandev/internal/db" "github.com/kandev/kandev/internal/task/models" taskservice "github.com/kandev/kandev/internal/task/service" "github.com/kandev/kandev/internal/worktree" diff --git a/apps/backend/cmd/mock-agent/mock_agent_test.go b/apps/backend/cmd/mock-agent/mock_agent_test.go index 8cc3226cad..1f7da9538a 100644 --- a/apps/backend/cmd/mock-agent/mock_agent_test.go +++ b/apps/backend/cmd/mock-agent/mock_agent_test.go @@ -55,11 +55,11 @@ func TestParseModelFromArgs(t *testing.T) { func TestDelayRange(t *testing.T) { tests := []struct { - model string - wantMinLo int - wantMinHi int - wantMaxLo int - wantMaxHi int + model string + wantMinLo int + wantMinHi int + wantMaxLo int + wantMaxHi int }{ {"mock-fast", 10, 10, 50, 50}, {"mock-slow", 500, 500, 3000, 3000}, diff --git a/apps/backend/cmd/mock-agent/types.go b/apps/backend/cmd/mock-agent/types.go index edd7af9612..e9c99ace60 100644 --- a/apps/backend/cmd/mock-agent/types.go +++ b/apps/backend/cmd/mock-agent/types.go @@ -22,8 +22,8 @@ const ( // Tool names matching Claude Code conventions const ( - ToolBash = "Bash" - ToolEdit = "Edit" + ToolBash = "Bash" + ToolEdit = "Edit" ToolRead = "Read" ToolGlob = "Glob" ToolGrep = "Grep" @@ -69,8 +69,8 @@ type SystemMsg struct { // AssistantMsg is an assistant message with content blocks. type AssistantMsg struct { - Type string `json:"type"` - ParentToolUseID string `json:"parent_tool_use_id,omitempty"` + Type string `json:"type"` + ParentToolUseID string `json:"parent_tool_use_id,omitempty"` Message AssistantBody `json:"message"` } @@ -114,9 +114,9 @@ type Usage struct { // UserMsg is a user message (used for tool results). type UserMsg struct { - Type string `json:"type"` - ParentToolUseID string `json:"parent_tool_use_id,omitempty"` - Message UserMsgBody `json:"message"` + Type string `json:"type"` + ParentToolUseID string `json:"parent_tool_use_id,omitempty"` + Message UserMsgBody `json:"message"` } // UserMsgBody is the body of a user message with tool results. @@ -127,15 +127,15 @@ type UserMsgBody struct { // ResultMsg is the final result message for a turn. type ResultMsg struct { - Type string `json:"type"` - Result json.RawMessage `json:"result"` - CostUSD float64 `json:"cost_usd"` - DurationMS int64 `json:"duration_ms"` - DurationAPIMS int64 `json:"duration_api_ms"` - IsError bool `json:"is_error"` - NumTurns int `json:"num_turns"` - TotalInputTokens int64 `json:"total_input_tokens"` - TotalOutputTokens int64 `json:"total_output_tokens"` + Type string `json:"type"` + Result json.RawMessage `json:"result"` + CostUSD float64 `json:"cost_usd"` + DurationMS int64 `json:"duration_ms"` + DurationAPIMS int64 `json:"duration_api_ms"` + IsError bool `json:"is_error"` + NumTurns int `json:"num_turns"` + TotalInputTokens int64 `json:"total_input_tokens"` + TotalOutputTokens int64 `json:"total_output_tokens"` ModelUsage map[string]ModelUsageStats `json:"model_usage,omitempty"` } @@ -152,9 +152,9 @@ type ResultData struct { // ControlRequestMsg is a control request emitted to stdout (permission requests). type ControlRequestMsg struct { - Type string `json:"type"` - RequestID string `json:"request_id"` - Request ControlRequestBody `json:"request"` + Type string `json:"type"` + RequestID string `json:"request_id"` + Request ControlRequestBody `json:"request"` } // ControlRequestBody is the body of a control request. @@ -167,15 +167,15 @@ type ControlRequestBody struct { // ControlResponseMsg is a control response emitted to stdout (for initialize). type ControlResponseMsg struct { - Type string `json:"type"` - Response ControlResponseBody `json:"response"` + Type string `json:"type"` + Response ControlResponseBody `json:"response"` } // ControlResponseBody is the body of a control response. type ControlResponseBody struct { - Subtype string `json:"subtype"` - RequestID string `json:"request_id"` - Response *InitializeResponse `json:"response,omitempty"` + Subtype string `json:"subtype"` + RequestID string `json:"request_id"` + Response *InitializeResponse `json:"response,omitempty"` } // InitializeResponse is the response to an initialize control request. diff --git a/apps/backend/internal/agent/agents/amp.go b/apps/backend/internal/agent/agents/amp.go index 8d4bb8fffa..f6aa1200d3 100644 --- a/apps/backend/internal/agent/agents/amp.go +++ b/apps/backend/internal/agent/agents/amp.go @@ -46,8 +46,8 @@ func (a *Amp) DisplayName() string { return "Amp" } func (a *Amp) Description() string { return "Sourcegraph Amp CLI-powered autonomous coding agent using stream-json protocol." } -func (a *Amp) Enabled() bool { return true } -func (a *Amp) DisplayOrder() int { return 7 } +func (a *Amp) Enabled() bool { return true } +func (a *Amp) DisplayOrder() int { return 7 } func (a *Amp) Logo(v LogoVariant) []byte { if v == LogoDark { diff --git a/apps/backend/internal/agent/agents/auggie.go b/apps/backend/internal/agent/agents/auggie.go index 30faed9a09..51f6e3defa 100644 --- a/apps/backend/internal/agent/agents/auggie.go +++ b/apps/backend/internal/agent/agents/auggie.go @@ -50,8 +50,8 @@ func (a *Auggie) ID() string { return "auggie" } func (a *Auggie) Name() string { return "Augment Coding Agent" } func (a *Auggie) DisplayName() string { return "Auggie" } func (a *Auggie) Description() string { return "Auggie CLI-powered autonomous coding agent." } -func (a *Auggie) Enabled() bool { return true } -func (a *Auggie) DisplayOrder() int { return 3 } +func (a *Auggie) Enabled() bool { return true } +func (a *Auggie) DisplayOrder() int { return 3 } func (a *Auggie) Logo(v LogoVariant) []byte { if v == LogoDark { @@ -100,10 +100,10 @@ func (a *Auggie) BuildCommand(opts CommandOptions) Command { func (a *Auggie) Runtime() *RuntimeConfig { canRecover := false return &RuntimeConfig{ - Image: "kandev/multi-agent", - Tag: "latest", - Cmd: Cmd("npx", "-y", "@augmentcode/auggie@0.15.0", "--acp").Build(), - WorkingDir: "/workspace", + Image: "kandev/multi-agent", + Tag: "latest", + Cmd: Cmd("npx", "-y", "@augmentcode/auggie@0.15.0", "--acp").Build(), + WorkingDir: "/workspace", RequiredEnv: []string{"AUGMENT_SESSION_AUTH"}, Env: map[string]string{}, Mounts: []MountTemplate{ diff --git a/apps/backend/internal/agent/agents/auggie_test.go b/apps/backend/internal/agent/agents/auggie_test.go index c730dec299..98d59f48b4 100644 --- a/apps/backend/internal/agent/agents/auggie_test.go +++ b/apps/backend/internal/agent/agents/auggie_test.go @@ -25,12 +25,12 @@ func assertDefaultModel(t *testing.T, models []Model, wantDef string) { func TestAuggieParseModels(t *testing.T) { tests := []struct { - name string - input string - wantLen int - wantErr bool - wantIDs []string - wantDef string // expected default model ID + name string + input string + wantLen int + wantErr bool + wantIDs []string + wantDef string // expected default model ID }{ { name: "normal output with descriptions", diff --git a/apps/backend/internal/agent/agents/claude_code.go b/apps/backend/internal/agent/agents/claude_code.go index 243d71d455..00b601428d 100644 --- a/apps/backend/internal/agent/agents/claude_code.go +++ b/apps/backend/internal/agent/agents/claude_code.go @@ -48,8 +48,8 @@ func (a *ClaudeCode) DisplayName() string { return "Claude" } func (a *ClaudeCode) Description() string { return "Anthropic Claude Code CLI-powered autonomous coding agent using the stream-json protocol." } -func (a *ClaudeCode) Enabled() bool { return true } -func (a *ClaudeCode) DisplayOrder() int { return 1 } +func (a *ClaudeCode) Enabled() bool { return true } +func (a *ClaudeCode) DisplayOrder() int { return 1 } func (a *ClaudeCode) Logo(v LogoVariant) []byte { if v == LogoDark { diff --git a/apps/backend/internal/agent/agents/codex.go b/apps/backend/internal/agent/agents/codex.go index 43cd05243d..1df7fb81f8 100644 --- a/apps/backend/internal/agent/agents/codex.go +++ b/apps/backend/internal/agent/agents/codex.go @@ -46,8 +46,8 @@ func (a *Codex) DisplayName() string { return "Codex" } func (a *Codex) Description() string { return "OpenAI Codex CLI-powered autonomous coding agent using the Codex app-server protocol." } -func (a *Codex) Enabled() bool { return true } -func (a *Codex) DisplayOrder() int { return 2 } +func (a *Codex) Enabled() bool { return true } +func (a *Codex) DisplayOrder() int { return 2 } func (a *Codex) Logo(v LogoVariant) []byte { if v == LogoDark { @@ -79,7 +79,6 @@ func (a *Codex) BuildCommand(opts CommandOptions) Command { Build() } - func (a *Codex) Runtime() *RuntimeConfig { canRecover := true return &RuntimeConfig{ diff --git a/apps/backend/internal/agent/agents/copilot.go b/apps/backend/internal/agent/agents/copilot.go index 41c41f9082..8a0339aea1 100644 --- a/apps/backend/internal/agent/agents/copilot.go +++ b/apps/backend/internal/agent/agents/copilot.go @@ -47,8 +47,8 @@ func (a *Copilot) DisplayName() string { return "Copilot" } func (a *Copilot) Description() string { return "GitHub Copilot CLI-powered autonomous coding agent using the Copilot SDK protocol." } -func (a *Copilot) Enabled() bool { return true } -func (a *Copilot) DisplayOrder() int { return 6 } +func (a *Copilot) Enabled() bool { return true } +func (a *Copilot) DisplayOrder() int { return 6 } func (a *Copilot) Logo(v LogoVariant) []byte { if v == LogoDark { @@ -92,7 +92,6 @@ func (a *Copilot) BuildCommand(opts CommandOptions) Command { Build() } - func (a *Copilot) Runtime() *RuntimeConfig { canRecover := true return &RuntimeConfig{ diff --git a/apps/backend/internal/agent/agents/gemini.go b/apps/backend/internal/agent/agents/gemini.go index 4ae45d422c..e231d29a25 100644 --- a/apps/backend/internal/agent/agents/gemini.go +++ b/apps/backend/internal/agent/agents/gemini.go @@ -48,8 +48,8 @@ func (a *Gemini) DisplayName() string { return "Gemini" } func (a *Gemini) Description() string { return "Google Gemini CLI-powered autonomous coding agent using ACP protocol." } -func (a *Gemini) Enabled() bool { return true } -func (a *Gemini) DisplayOrder() int { return 5 } +func (a *Gemini) Enabled() bool { return true } +func (a *Gemini) DisplayOrder() int { return 5 } func (a *Gemini) Logo(v LogoVariant) []byte { if v == LogoDark { diff --git a/apps/backend/internal/agent/agents/helpers.go b/apps/backend/internal/agent/agents/helpers.go index 5f9824574c..04ef99c9b4 100644 --- a/apps/backend/internal/agent/agents/helpers.go +++ b/apps/backend/internal/agent/agents/helpers.go @@ -126,4 +126,3 @@ func execAndParse(ctx context.Context, timeout time.Duration, parse func(string) return parse(stdout.String()) } - diff --git a/apps/backend/internal/agent/agents/mock.go b/apps/backend/internal/agent/agents/mock.go index 05d4f8f321..6c48c373df 100644 --- a/apps/backend/internal/agent/agents/mock.go +++ b/apps/backend/internal/agent/agents/mock.go @@ -35,8 +35,8 @@ func (a *MockAgent) DisplayName() string { return "Mock" } func (a *MockAgent) Description() string { return "Mock agent for testing. Generates simulated responses with all message types." } -func (a *MockAgent) Enabled() bool { return a.enabled } -func (a *MockAgent) DisplayOrder() int { return 99 } +func (a *MockAgent) Enabled() bool { return a.enabled } +func (a *MockAgent) DisplayOrder() int { return 99 } func (a *MockAgent) Logo(v LogoVariant) []byte { if v == LogoDark { @@ -69,9 +69,9 @@ func (a *MockAgent) BuildCommand(opts CommandOptions) Command { func (a *MockAgent) Runtime() *RuntimeConfig { canRecover := false return &RuntimeConfig{ - Cmd: Cmd("mock-agent").Build(), - WorkingDir: "{workspace}", - Env: map[string]string{}, + Cmd: Cmd("mock-agent").Build(), + WorkingDir: "{workspace}", + Env: map[string]string{}, ResourceLimits: ResourceLimits{MemoryMB: 512, CPUCores: 0.5, Timeout: time.Hour}, Protocol: agent.ProtocolClaudeCode, ModelFlag: NewParam("--model", "{model}"), diff --git a/apps/backend/internal/agent/agents/opencode.go b/apps/backend/internal/agent/agents/opencode.go index d773191b4b..18598082d8 100644 --- a/apps/backend/internal/agent/agents/opencode.go +++ b/apps/backend/internal/agent/agents/opencode.go @@ -49,8 +49,8 @@ func (a *OpenCode) DisplayName() string { return "OpenCode" } func (a *OpenCode) Description() string { return "OpenCode CLI-powered autonomous coding agent using REST/SSE protocol." } -func (a *OpenCode) Enabled() bool { return true } -func (a *OpenCode) DisplayOrder() int { return 4 } +func (a *OpenCode) Enabled() bool { return true } +func (a *OpenCode) DisplayOrder() int { return 4 } func (a *OpenCode) Logo(v LogoVariant) []byte { if v == LogoDark { diff --git a/apps/backend/internal/agent/controller/errors.go b/apps/backend/internal/agent/controller/errors.go index eb01f54a1d..7b4f42d9f8 100644 --- a/apps/backend/internal/agent/controller/errors.go +++ b/apps/backend/internal/agent/controller/errors.go @@ -12,4 +12,3 @@ var ( // ErrAgentNotFound is returned when agent is not found ErrAgentNotFound = errors.New("agent not found") ) - diff --git a/apps/backend/internal/agent/credentials/augment_provider.go b/apps/backend/internal/agent/credentials/augment_provider.go index f1494f8210..e350e34330 100644 --- a/apps/backend/internal/agent/credentials/augment_provider.go +++ b/apps/backend/internal/agent/credentials/augment_provider.go @@ -99,4 +99,3 @@ func (p *AugmentSessionProvider) ListAvailable(ctx context.Context) ([]string, e return []string{}, nil } - diff --git a/apps/backend/internal/agent/credentials/env_provider.go b/apps/backend/internal/agent/credentials/env_provider.go index 55605e98b6..95eb37a20c 100644 --- a/apps/backend/internal/agent/credentials/env_provider.go +++ b/apps/backend/internal/agent/credentials/env_provider.go @@ -138,4 +138,3 @@ func (p *EnvProvider) ListAvailable(ctx context.Context) ([]string, error) { return available, nil } - diff --git a/apps/backend/internal/agent/credentials/file_provider.go b/apps/backend/internal/agent/credentials/file_provider.go index 3196540ebf..269ef9ad60 100644 --- a/apps/backend/internal/agent/credentials/file_provider.go +++ b/apps/backend/internal/agent/credentials/file_provider.go @@ -111,4 +111,3 @@ func (p *FileProvider) Reload() error { return p.load() } - diff --git a/apps/backend/internal/agent/credentials/manager.go b/apps/backend/internal/agent/credentials/manager.go index dc0000f8c8..9ae10bca17 100644 --- a/apps/backend/internal/agent/credentials/manager.go +++ b/apps/backend/internal/agent/credentials/manager.go @@ -182,4 +182,3 @@ func (m *Manager) ClearCache() { m.cache = make(map[string]*Credential) m.logger.Debug("credential cache cleared") } - diff --git a/apps/backend/internal/agent/dto/dto.go b/apps/backend/internal/agent/dto/dto.go index 25dbff7b9b..ea50ce33f2 100644 --- a/apps/backend/internal/agent/dto/dto.go +++ b/apps/backend/internal/agent/dto/dto.go @@ -73,8 +73,8 @@ type ListAgentTypesRequest struct{} // AgentTypeDTO represents an agent type type AgentTypeDTO struct { - ID string `json:"id"` - Name string `json:"name"` + ID string `json:"id"` + Name string `json:"name"` Description string `json:"description,omitempty"` Image string `json:"image"` Enabled bool `json:"enabled"` @@ -124,7 +124,7 @@ type AgentExecutionData struct { // FromAgentType converts a registry.AgentType to AgentTypeDTO func FromAgentType(t *AgentTypeData) AgentTypeDTO { return AgentTypeDTO{ - ID: t.ID, + ID: t.ID, Name: t.Name, Description: t.Description, Image: t.Image, @@ -140,4 +140,3 @@ type AgentTypeData struct { Image string Enabled bool } - diff --git a/apps/backend/internal/agent/handlers/git_handlers.go b/apps/backend/internal/agent/handlers/git_handlers.go index a39c99a1b5..ac9efdca14 100644 --- a/apps/backend/internal/agent/handlers/git_handlers.go +++ b/apps/backend/internal/agent/handlers/git_handlers.go @@ -413,4 +413,3 @@ func (h *GitHandlers) getAgentCtlClient(sessionID string) (*client.Client, error return c, nil } - diff --git a/apps/backend/internal/agent/handlers/handlers.go b/apps/backend/internal/agent/handlers/handlers.go index 3bd9f06673..3c594b5313 100644 --- a/apps/backend/internal/agent/handlers/handlers.go +++ b/apps/backend/internal/agent/handlers/handlers.go @@ -159,4 +159,3 @@ func (h *Handlers) wsListAgentTypes(ctx context.Context, msg *ws.Message) (*ws.M } return ws.NewResponse(msg.ID, msg.Action, resp) } - diff --git a/apps/backend/internal/agent/handlers/workspace_file_handlers.go b/apps/backend/internal/agent/handlers/workspace_file_handlers.go index 5f790155bf..d064f4f205 100644 --- a/apps/backend/internal/agent/handlers/workspace_file_handlers.go +++ b/apps/backend/internal/agent/handlers/workspace_file_handlers.go @@ -4,8 +4,8 @@ import ( "context" "fmt" - agentctl "github.com/kandev/kandev/internal/agentctl/client" "github.com/kandev/kandev/internal/agent/lifecycle" + agentctl "github.com/kandev/kandev/internal/agentctl/client" "github.com/kandev/kandev/internal/common/logger" ws "github.com/kandev/kandev/pkg/websocket" "go.uber.org/zap" @@ -13,8 +13,8 @@ import ( // WorkspaceFileHandlers handles workspace file operations type WorkspaceFileHandlers struct { - lifecycle *lifecycle.Manager - logger *logger.Logger + lifecycle *lifecycle.Manager + logger *logger.Logger } // NewWorkspaceFileHandlers creates new workspace file handlers diff --git a/apps/backend/internal/agent/lifecycle/container.go b/apps/backend/internal/agent/lifecycle/container.go index 393a583e9d..fcbb4193bb 100644 --- a/apps/backend/internal/agent/lifecycle/container.go +++ b/apps/backend/internal/agent/lifecycle/container.go @@ -11,9 +11,9 @@ import ( "go.uber.org/zap" - agentctl "github.com/kandev/kandev/internal/agentctl/client" "github.com/kandev/kandev/internal/agent/agents" "github.com/kandev/kandev/internal/agent/docker" + agentctl "github.com/kandev/kandev/internal/agentctl/client" "github.com/kandev/kandev/internal/common/logger" ) diff --git a/apps/backend/internal/agent/lifecycle/event_types.go b/apps/backend/internal/agent/lifecycle/event_types.go index 8fccd2d78f..0df30c6458 100644 --- a/apps/backend/internal/agent/lifecycle/event_types.go +++ b/apps/backend/internal/agent/lifecycle/event_types.go @@ -294,11 +294,11 @@ func (p ContextWindowEventPayload) GetSessionID() string { // AvailableCommandsEventPayload is the payload for available commands update events. type AvailableCommandsEventPayload struct { - TaskID string `json:"task_id"` - SessionID string `json:"session_id"` - AgentID string `json:"agent_id"` + TaskID string `json:"task_id"` + SessionID string `json:"session_id"` + AgentID string `json:"agent_id"` AvailableCommands []streams.AvailableCommand `json:"available_commands"` - Timestamp string `json:"timestamp"` + Timestamp string `json:"timestamp"` } // GetSessionID returns the session ID for this event (used by event routing). diff --git a/apps/backend/internal/agent/lifecycle/execution_store.go b/apps/backend/internal/agent/lifecycle/execution_store.go index 015bffe980..e1c0377510 100644 --- a/apps/backend/internal/agent/lifecycle/execution_store.go +++ b/apps/backend/internal/agent/lifecycle/execution_store.go @@ -144,8 +144,6 @@ func (s *ExecutionStore) UpdateError(executionID string, errorMsg string) { } } - - // WithLock executes a function with the store lock held, providing access to the execution. // Returns ErrExecutionNotFound if the execution doesn't exist. // The function should be fast to avoid blocking other operations. diff --git a/apps/backend/internal/agent/lifecycle/manager_events.go b/apps/backend/internal/agent/lifecycle/manager_events.go index d68531fd9a..1511e4fd0d 100644 --- a/apps/backend/internal/agent/lifecycle/manager_events.go +++ b/apps/backend/internal/agent/lifecycle/manager_events.go @@ -349,4 +349,3 @@ func (m *Manager) handleProcessStatus(execution *AgentExecution, status *agentct func (m *Manager) handleShellExit(execution *AgentExecution, code int) { m.eventPublisher.PublishShellExit(execution, code) } - diff --git a/apps/backend/internal/agent/lifecycle/manager_launch.go b/apps/backend/internal/agent/lifecycle/manager_launch.go index 5d72fd628f..e018b1b147 100644 --- a/apps/backend/internal/agent/lifecycle/manager_launch.go +++ b/apps/backend/internal/agent/lifecycle/manager_launch.go @@ -388,4 +388,3 @@ func (m *Manager) initializeAgentSession(ctx context.Context, execution *AgentEx m.finalizeBootMessage(bootMsg, bootStopCh, execution.agentctl, containerStateExited) return nil } - diff --git a/apps/backend/internal/agent/lifecycle/runtime_registry_test.go b/apps/backend/internal/agent/lifecycle/runtime_registry_test.go index 4f9533112b..3a678dff39 100644 --- a/apps/backend/internal/agent/lifecycle/runtime_registry_test.go +++ b/apps/backend/internal/agent/lifecycle/runtime_registry_test.go @@ -290,7 +290,6 @@ func TestRuntimeRegistry_RecoverAll(t *testing.T) { }) } - func TestRuntimeRegistry_ThreadSafety(t *testing.T) { log := newTestRegistryLogger() registry := NewRuntimeRegistry(log) @@ -349,4 +348,3 @@ func TestRuntimeRegistry_ThreadSafety(t *testing.T) { // If we reach here without a race condition panic, the test passes // The -race flag during testing will detect actual race conditions } - diff --git a/apps/backend/internal/agent/lifecycle/session.go b/apps/backend/internal/agent/lifecycle/session.go index 40477ee54d..7bd51438e1 100644 --- a/apps/backend/internal/agent/lifecycle/session.go +++ b/apps/backend/internal/agent/lifecycle/session.go @@ -15,8 +15,8 @@ import ( "github.com/kandev/kandev/internal/common/constants" "github.com/kandev/kandev/internal/common/logger" "github.com/kandev/kandev/internal/sysprompt" - v1 "github.com/kandev/kandev/pkg/api/v1" "github.com/kandev/kandev/pkg/agent" + v1 "github.com/kandev/kandev/pkg/api/v1" ) // SessionManager handles ACP session initialization and management diff --git a/apps/backend/internal/agent/lifecycle/session_history.go b/apps/backend/internal/agent/lifecycle/session_history.go index ad0ed0bcbd..99f0b74e90 100644 --- a/apps/backend/internal/agent/lifecycle/session_history.go +++ b/apps/backend/internal/agent/lifecycle/session_history.go @@ -36,15 +36,15 @@ type SessionHistoryManager struct { // HistoryEntry represents a single entry in the session history. type HistoryEntry struct { - Timestamp time.Time `json:"timestamp"` - Type string `json:"type"` // "user_message", "agent_message", "tool_call", "tool_result" - Role string `json:"role,omitempty"` - Content string `json:"content,omitempty"` - ToolName string `json:"tool_name,omitempty"` - ToolCallID string `json:"tool_call_id,omitempty"` - ToolStatus string `json:"tool_status,omitempty"` - SessionID string `json:"session_id,omitempty"` - OperationID string `json:"operation_id,omitempty"` + Timestamp time.Time `json:"timestamp"` + Type string `json:"type"` // "user_message", "agent_message", "tool_call", "tool_result" + Role string `json:"role,omitempty"` + Content string `json:"content,omitempty"` + ToolName string `json:"tool_name,omitempty"` + ToolCallID string `json:"tool_call_id,omitempty"` + ToolStatus string `json:"tool_status,omitempty"` + SessionID string `json:"session_id,omitempty"` + OperationID string `json:"operation_id,omitempty"` } // NewSessionHistoryManager creates a new SessionHistoryManager. diff --git a/apps/backend/internal/agent/lifecycle/session_test.go b/apps/backend/internal/agent/lifecycle/session_test.go index 1261d423ae..940e1fbb0d 100644 --- a/apps/backend/internal/agent/lifecycle/session_test.go +++ b/apps/backend/internal/agent/lifecycle/session_test.go @@ -30,8 +30,8 @@ func newSessionTestLogger() *logger.Logger { // mockAgentServer creates a test WebSocket server simulating agentctl. // It responds to agent stream requests and tracks which actions were called and in what order. type mockAgentServer struct { - server *httptest.Server - mu sync.Mutex + server *httptest.Server + mu sync.Mutex actionLog []string // ordered log of actions received upgrader websocket.Upgrader handler func(msg ws.Message) *ws.Message diff --git a/apps/backend/internal/agent/registry/registry_test.go b/apps/backend/internal/agent/registry/registry_test.go index 76edaa9ee6..f87c8d32fc 100644 --- a/apps/backend/internal/agent/registry/registry_test.go +++ b/apps/backend/internal/agent/registry/registry_test.go @@ -19,8 +19,8 @@ type testAgent struct { runtime *agents.RuntimeConfig } -func (a *testAgent) ID() string { return a.id } -func (a *testAgent) Name() string { return a.name } +func (a *testAgent) ID() string { return a.id } +func (a *testAgent) Name() string { return a.name } func (a *testAgent) DisplayName() string { return a.name } func (a *testAgent) Description() string { return a.description } func (a *testAgent) Enabled() bool { return a.enabled } @@ -58,9 +58,9 @@ func validAgentConfig(id, name string) *testAgent { Tag: "latest", WorkingDir: "/workspace", ResourceLimits: agents.ResourceLimits{ - MemoryMB: 1024, - CPUCores: 1.0, - Timeout: time.Hour, + MemoryMB: 1024, + CPUCores: 1.0, + Timeout: time.Hour, }, }, } diff --git a/apps/backend/internal/agent/settings/controller/controller_test.go b/apps/backend/internal/agent/settings/controller/controller_test.go index 344e7384fa..ef307fe380 100644 --- a/apps/backend/internal/agent/settings/controller/controller_test.go +++ b/apps/backend/internal/agent/settings/controller/controller_test.go @@ -35,7 +35,6 @@ func (a *testAgent) DisplayOrder() int { return 0 } func (a *testAgent) Logo(v agents.LogoVariant) []byte { return a.logoData } - func (a *testAgent) IsInstalled(ctx context.Context) (*agents.DiscoveryResult, error) { return &agents.DiscoveryResult{Available: false}, nil } diff --git a/apps/backend/internal/agentctl/client/agent.go b/apps/backend/internal/agentctl/client/agent.go index 4a3a95c3ba..a9eed389b5 100644 --- a/apps/backend/internal/agentctl/client/agent.go +++ b/apps/backend/internal/agentctl/client/agent.go @@ -342,6 +342,7 @@ func (c *Client) Cancel(ctx context.Context) error { } return nil } + // GetAgentStderr returns recent stderr lines from the agent process via the agent WebSocket stream. func (c *Client) GetAgentStderr(ctx context.Context) ([]string, error) { resp, err := c.sendStreamRequest(ctx, "agent.stderr", nil) diff --git a/apps/backend/internal/agentctl/client/launcher/launcher.go b/apps/backend/internal/agentctl/client/launcher/launcher.go index 30f2633383..d04ce1b2f2 100644 --- a/apps/backend/internal/agentctl/client/launcher/launcher.go +++ b/apps/backend/internal/agentctl/client/launcher/launcher.go @@ -231,8 +231,6 @@ func (l *Launcher) Stop(ctx context.Context) error { } } - - // checkPortAvailable verifies the given port is not in use. // It checks by attempting a wildcard bind (matching what agentctl does with ":port"). func checkPortAvailable(port int) error { diff --git a/apps/backend/internal/agentctl/server/acp/client.go b/apps/backend/internal/agentctl/server/acp/client.go index b2b00b1e25..ed5c635fab 100644 --- a/apps/backend/internal/agentctl/server/acp/client.go +++ b/apps/backend/internal/agentctl/server/acp/client.go @@ -351,4 +351,3 @@ func (c *Client) WaitForTerminalExit(ctx context.Context, p acp.WaitForTerminalE // Verify interface implementation var _ acp.Client = (*Client)(nil) - diff --git a/apps/backend/internal/agentctl/server/adapter/amp_adapter.go b/apps/backend/internal/agentctl/server/adapter/amp_adapter.go index c1b618c40b..b5fd18fe05 100644 --- a/apps/backend/internal/agentctl/server/adapter/amp_adapter.go +++ b/apps/backend/internal/agentctl/server/adapter/amp_adapter.go @@ -13,8 +13,8 @@ import ( "github.com/kandev/kandev/internal/agentctl/types" "github.com/kandev/kandev/internal/agentctl/types/streams" "github.com/kandev/kandev/internal/common/logger" - v1 "github.com/kandev/kandev/pkg/api/v1" "github.com/kandev/kandev/pkg/amp" + v1 "github.com/kandev/kandev/pkg/api/v1" "go.uber.org/zap" ) diff --git a/apps/backend/internal/agentctl/server/adapter/copilot_adapter.go b/apps/backend/internal/agentctl/server/adapter/copilot_adapter.go index 34e2244b29..a0fdf9b869 100644 --- a/apps/backend/internal/agentctl/server/adapter/copilot_adapter.go +++ b/apps/backend/internal/agentctl/server/adapter/copilot_adapter.go @@ -373,8 +373,8 @@ func (a *CopilotAdapter) Prompt(ctx context.Context, message string, _ []v1.Mess operationID := uuid.New().String() a.operationID = operationID a.resultCh = make(chan resultComplete, 1) - a.completeSent = false // Reset completion flag for new operation - a.receivedDeltas = false // Reset delta tracking for new operation + a.completeSent = false // Reset completion flag for new operation + a.receivedDeltas = false // Reset delta tracking for new operation a.mu.Unlock() a.logger.Info("sending prompt via SDK", @@ -982,7 +982,7 @@ func (a *CopilotAdapter) resolvePermissionActionDetails( if se := cachedPayload.ShellExec(); se != nil { return se.Command, types.ActionTypeCommand, map[string]interface{}{ "command": se.Command, - "cwd": se.WorkDir, + "cwd": se.WorkDir, } } case streams.ToolKindModifyFile: diff --git a/apps/backend/internal/agentctl/server/adapter/transport/codex/normalize.go b/apps/backend/internal/agentctl/server/adapter/transport/codex/normalize.go index 25f14a17f3..e13f655bc6 100644 --- a/apps/backend/internal/agentctl/server/adapter/transport/codex/normalize.go +++ b/apps/backend/internal/agentctl/server/adapter/transport/codex/normalize.go @@ -167,4 +167,3 @@ func (n *Normalizer) normalizeCommandResult(payload *streams.ShellExecPayload, r } } } - diff --git a/apps/backend/internal/agentctl/server/adapter/transport/streamjson/streamjson_permissions.go b/apps/backend/internal/agentctl/server/adapter/transport/streamjson/streamjson_permissions.go index f0773c7282..b68b7afad4 100644 --- a/apps/backend/internal/agentctl/server/adapter/transport/streamjson/streamjson_permissions.go +++ b/apps/backend/internal/agentctl/server/adapter/transport/streamjson/streamjson_permissions.go @@ -159,4 +159,3 @@ func (a *Adapter) handleHookCallback(requestID string, req *claudecode.ControlRe a.logger.Warn("failed to send hook callback response", zap.Error(err)) } } - diff --git a/apps/backend/internal/agentctl/server/instance/instance.go b/apps/backend/internal/agentctl/server/instance/instance.go index 494cbcc959..c4f61e84bb 100644 --- a/apps/backend/internal/agentctl/server/instance/instance.go +++ b/apps/backend/internal/agentctl/server/instance/instance.go @@ -142,4 +142,3 @@ func (i *Instance) Info() *InstanceInfo { CreatedAt: i.CreatedAt, } } - diff --git a/apps/backend/internal/agentctl/server/mcp/backend_client.go b/apps/backend/internal/agentctl/server/mcp/backend_client.go index 617333ced6..accc8447e1 100644 --- a/apps/backend/internal/agentctl/server/mcp/backend_client.go +++ b/apps/backend/internal/agentctl/server/mcp/backend_client.go @@ -123,4 +123,3 @@ func (c *ChannelBackendClient) RequestPayload(ctx context.Context, action string func (c *ChannelBackendClient) Close() { close(c.requestCh) } - diff --git a/apps/backend/internal/agentctl/server/mcp/handlers.go b/apps/backend/internal/agentctl/server/mcp/handlers.go index 5f615a6da9..4fb2f4320a 100644 --- a/apps/backend/internal/agentctl/server/mcp/handlers.go +++ b/apps/backend/internal/agentctl/server/mcp/handlers.go @@ -364,4 +364,3 @@ func (s *Server) deleteTaskPlanHandler() server.ToolHandlerFunc { return mcp.NewToolResultText("Plan deleted successfully."), nil } } - diff --git a/apps/backend/internal/agentctl/server/process/cmdline_test.go b/apps/backend/internal/agentctl/server/process/cmdline_test.go index ba4c4b9811..ff45bd3a9e 100644 --- a/apps/backend/internal/agentctl/server/process/cmdline_test.go +++ b/apps/backend/internal/agentctl/server/process/cmdline_test.go @@ -14,11 +14,11 @@ func TestEscapeArg(t *testing.T) { {"with tab", "hello\tworld", `"hello` + "\t" + `world"`}, {"with quote", `say "hi"`, `"say \"hi\""`}, {"backslash no quote", `a\b`, `a\b`}, - {"backslash before quote", `a\"`, `a\\\"` }, + {"backslash before quote", `a\"`, `a\\\"`}, {"trailing backslash with space", `a b\`, `"a b\\"`}, {"multiple trailing backslashes with space", `a b\\`, `"a b\\\\"`}, {"only backslashes", `\\`, `\\`}, - {"backslash then quote", `\\"`, `\\\\\"` }, + {"backslash then quote", `\\"`, `\\\\\"`}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/apps/backend/internal/agentctl/server/process/interactive_lifecycle.go b/apps/backend/internal/agentctl/server/process/interactive_lifecycle.go index 81019d2a17..6a35cc1a0d 100644 --- a/apps/backend/internal/agentctl/server/process/interactive_lifecycle.go +++ b/apps/backend/internal/agentctl/server/process/interactive_lifecycle.go @@ -36,12 +36,12 @@ type interactiveProcess struct { // Deferred start - process created lazily on first resize // This ensures PTY is created at exact frontend dimensions - started bool - startOnce sync.Once - startCmd []string - startDir string - startEnv map[string]string - startReq InteractiveStartRequest // Full request for deferred initialization + started bool + startOnce sync.Once + startCmd []string + startDir string + startEnv map[string]string + startReq InteractiveStartRequest // Full request for deferred initialization // Direct output - when set, raw output goes here instead of event bus directOutput DirectOutputWriter diff --git a/apps/backend/internal/agentctl/server/process/interactive_runner.go b/apps/backend/internal/agentctl/server/process/interactive_runner.go index b9d7ed9b29..50efc2742b 100644 --- a/apps/backend/internal/agentctl/server/process/interactive_runner.go +++ b/apps/backend/internal/agentctl/server/process/interactive_runner.go @@ -18,22 +18,22 @@ import ( // InteractiveStartRequest contains parameters for starting an interactive passthrough process. type InteractiveStartRequest struct { - SessionID string `json:"session_id"` // Required: Agent session owning this process - Command []string `json:"command"` // Required: Command and args to execute - WorkingDir string `json:"working_dir"` // Working directory - Env map[string]string `json:"env,omitempty"` // Additional environment variables - PromptPattern string `json:"prompt_pattern,omitempty"` // Regex pattern to detect agent prompt for turn completion - IdleTimeout time.Duration `json:"idle_timeout,omitempty"` // Idle timeout for turn detection - BufferMaxBytes int64 `json:"buffer_max_bytes,omitempty"` // Max output buffer size - StatusDetector string `json:"status_detector,omitempty"` // Status detector type: "claude_code", "codex", "" - CheckInterval time.Duration `json:"check_interval,omitempty"` // How often to check state (default 100ms) - StabilityWindow time.Duration `json:"stability_window,omitempty"` // State stability window (default 0) - ImmediateStart bool `json:"immediate_start,omitempty"` // Start immediately with default dimensions (don't wait for resize) - DefaultCols int `json:"default_cols,omitempty"` // Default columns if ImmediateStart (default 120) - DefaultRows int `json:"default_rows,omitempty"` // Default rows if ImmediateStart (default 40) - InitialCommand string `json:"initial_command,omitempty"` // Command to write to stdin after shell starts (for script terminals) - DisableTurnDetection bool `json:"disable_turn_detection,omitempty"` // Disable idle timer and turn detection (for user shell terminals) - IsUserShell bool `json:"is_user_shell,omitempty"` // Mark as user shell process (excluded from session-level lookups) + SessionID string `json:"session_id"` // Required: Agent session owning this process + Command []string `json:"command"` // Required: Command and args to execute + WorkingDir string `json:"working_dir"` // Working directory + Env map[string]string `json:"env,omitempty"` // Additional environment variables + PromptPattern string `json:"prompt_pattern,omitempty"` // Regex pattern to detect agent prompt for turn completion + IdleTimeout time.Duration `json:"idle_timeout,omitempty"` // Idle timeout for turn detection + BufferMaxBytes int64 `json:"buffer_max_bytes,omitempty"` // Max output buffer size + StatusDetector string `json:"status_detector,omitempty"` // Status detector type: "claude_code", "codex", "" + CheckInterval time.Duration `json:"check_interval,omitempty"` // How often to check state (default 100ms) + StabilityWindow time.Duration `json:"stability_window,omitempty"` // State stability window (default 0) + ImmediateStart bool `json:"immediate_start,omitempty"` // Start immediately with default dimensions (don't wait for resize) + DefaultCols int `json:"default_cols,omitempty"` // Default columns if ImmediateStart (default 120) + DefaultRows int `json:"default_rows,omitempty"` // Default rows if ImmediateStart (default 40) + InitialCommand string `json:"initial_command,omitempty"` // Command to write to stdin after shell starts (for script terminals) + DisableTurnDetection bool `json:"disable_turn_detection,omitempty"` // Disable idle timer and turn detection (for user shell terminals) + IsUserShell bool `json:"is_user_shell,omitempty"` // Mark as user shell process (excluded from session-level lookups) } // InteractiveProcessInfo represents the state of an interactive process. @@ -90,9 +90,9 @@ type userShellEntry struct { // InteractiveRunner manages interactive PTY-based processes with stdin support. type InteractiveRunner struct { - logger *logger.Logger - workspaceTracker *WorkspaceTracker - bufferMaxBytes int64 + logger *logger.Logger + workspaceTracker *WorkspaceTracker + bufferMaxBytes int64 turnCompleteCallback TurnCompleteCallback outputCallback OutputCallback statusCallback StatusCallback diff --git a/apps/backend/internal/agentctl/server/process/manager_test.go b/apps/backend/internal/agentctl/server/process/manager_test.go index 121c6d2cbd..e8cf3fd56a 100644 --- a/apps/backend/internal/agentctl/server/process/manager_test.go +++ b/apps/backend/internal/agentctl/server/process/manager_test.go @@ -30,15 +30,15 @@ func (s *stubAdapter) Connect(stdin io.Writer, stdout io.Reader) error { s.connectCalled = true return nil } -func (s *stubAdapter) Initialize(context.Context) error { return nil } -func (s *stubAdapter) GetAgentInfo() *adapter.AgentInfo { return nil } +func (s *stubAdapter) Initialize(context.Context) error { return nil } +func (s *stubAdapter) GetAgentInfo() *adapter.AgentInfo { return nil } func (s *stubAdapter) NewSession(_ context.Context, _ []types.McpServer) (string, error) { return "", nil } func (s *stubAdapter) LoadSession(context.Context, string) error { return nil } func (s *stubAdapter) Prompt(context.Context, string, []v1.MessageAttachment) error { return nil } func (s *stubAdapter) Cancel(context.Context) error { return nil } -func (s *stubAdapter) Updates() <-chan adapter.AgentEvent { return s.updatesCh } +func (s *stubAdapter) Updates() <-chan adapter.AgentEvent { return s.updatesCh } func (s *stubAdapter) GetSessionID() string { return "" } func (s *stubAdapter) GetOperationID() string { return "" } func (s *stubAdapter) SetPermissionHandler(adapter.PermissionHandler) {} diff --git a/apps/backend/internal/agentctl/server/process/procattr_linux.go b/apps/backend/internal/agentctl/server/process/procattr_linux.go index b4a49be881..d69105daae 100644 --- a/apps/backend/internal/agentctl/server/process/procattr_linux.go +++ b/apps/backend/internal/agentctl/server/process/procattr_linux.go @@ -24,4 +24,3 @@ func killProcessGroup(pid int) error { // Kill the entire process group by using negative PID return syscall.Kill(-pid, syscall.SIGKILL) } - diff --git a/apps/backend/internal/agentctl/server/process/procattr_unix.go b/apps/backend/internal/agentctl/server/process/procattr_unix.go index 29d1aadd22..7194742179 100644 --- a/apps/backend/internal/agentctl/server/process/procattr_unix.go +++ b/apps/backend/internal/agentctl/server/process/procattr_unix.go @@ -21,4 +21,3 @@ func killProcessGroup(pid int) error { // Kill the entire process group by using negative PID return syscall.Kill(-pid, syscall.SIGKILL) } - diff --git a/apps/backend/internal/agentctl/server/process/procattr_windows.go b/apps/backend/internal/agentctl/server/process/procattr_windows.go index 8fa5dfb567..cf46649a29 100644 --- a/apps/backend/internal/agentctl/server/process/procattr_windows.go +++ b/apps/backend/internal/agentctl/server/process/procattr_windows.go @@ -26,4 +26,3 @@ func killProcessGroup(pid int) error { kill := exec.Command("taskkill", "/F", "/T", "/PID", fmt.Sprintf("%d", pid)) return kill.Run() } - diff --git a/apps/backend/internal/agentctl/server/process/pty_windows.go b/apps/backend/internal/agentctl/server/process/pty_windows.go index a390a319ed..115f81c2d2 100644 --- a/apps/backend/internal/agentctl/server/process/pty_windows.go +++ b/apps/backend/internal/agentctl/server/process/pty_windows.go @@ -61,4 +61,3 @@ func startPTYWithSize(cmd *exec.Cmd, cols, rows int) (PtyHandle, error) { return &windowsPTY{cpty: cpty}, nil } - diff --git a/apps/backend/internal/agentctl/server/process/runner.go b/apps/backend/internal/agentctl/server/process/runner.go index 34b1429a9c..1a758453dc 100644 --- a/apps/backend/internal/agentctl/server/process/runner.go +++ b/apps/backend/internal/agentctl/server/process/runner.go @@ -12,10 +12,10 @@ // - Per-session process tracking // // Lifecycle: -// 1. Start() - Spawns process, creates output pipes, returns immediately -// 2. Background goroutines - Stream stdout/stderr, wait for exit -// 3. Stop() - Sends SIGTERM to process group, escalates to SIGKILL after 2s -// 4. Automatic cleanup - Process removed from tracking after exit +// 1. Start() - Spawns process, creates output pipes, returns immediately +// 2. Background goroutines - Stream stdout/stderr, wait for exit +// 3. Stop() - Sends SIGTERM to process group, escalates to SIGKILL after 2s +// 4. Automatic cleanup - Process removed from tracking after exit // // Use Cases: // - Agent-triggered builds (npm run build, go test ./...) @@ -43,12 +43,12 @@ import ( // StartProcessRequest contains parameters for starting a new background process. type StartProcessRequest struct { - SessionID string `json:"session_id"` // Required: Agent session owning this process - Kind types.ProcessKind `json:"kind"` // Process type (user_command, agent_script, etc.) - ScriptName string `json:"script_name,omitempty"` // Human-readable script identifier - Command string `json:"command"` // Required: Shell command to execute (passed to sh -lc) - WorkingDir string `json:"working_dir"` // Working directory (defaults to current dir) - Env map[string]string `json:"env,omitempty"` // Additional environment variables (merged with parent env) + SessionID string `json:"session_id"` // Required: Agent session owning this process + Kind types.ProcessKind `json:"kind"` // Process type (user_command, agent_script, etc.) + ScriptName string `json:"script_name,omitempty"` // Human-readable script identifier + Command string `json:"command"` // Required: Shell command to execute (passed to sh -lc) + WorkingDir string `json:"working_dir"` // Working directory (defaults to current dir) + Env map[string]string `json:"env,omitempty"` // Additional environment variables (merged with parent env) BufferMaxBytes int64 `json:"buffer_max_bytes,omitempty"` // Max output buffer size (defaults to runner's default) } @@ -59,17 +59,17 @@ type StopProcessRequest struct { // ProcessInfo represents the complete state of a background process. type ProcessInfo struct { - ID string `json:"id"` // Unique process identifier (UUID) - SessionID string `json:"session_id"` // Agent session that owns this process - Kind types.ProcessKind `json:"kind"` // Process classification + ID string `json:"id"` // Unique process identifier (UUID) + SessionID string `json:"session_id"` // Agent session that owns this process + Kind types.ProcessKind `json:"kind"` // Process classification ScriptName string `json:"script_name,omitempty"` // User-friendly name - Command string `json:"command"` // The shell command being executed - WorkingDir string `json:"working_dir"` // Execution directory - Status types.ProcessStatus `json:"status"` // Current state (starting, running, exited, failed) - ExitCode *int `json:"exit_code,omitempty"` // Process exit code (nil if still running) - StartedAt time.Time `json:"started_at"` // When the process was launched - UpdatedAt time.Time `json:"updated_at"` // Last status change timestamp - Output []ProcessOutputChunk `json:"output,omitempty"` // Buffered output (only included if requested) + Command string `json:"command"` // The shell command being executed + WorkingDir string `json:"working_dir"` // Execution directory + Status types.ProcessStatus `json:"status"` // Current state (starting, running, exited, failed) + ExitCode *int `json:"exit_code,omitempty"` // Process exit code (nil if still running) + StartedAt time.Time `json:"started_at"` // When the process was launched + UpdatedAt time.Time `json:"updated_at"` // Last status change timestamp + Output []ProcessOutputChunk `json:"output,omitempty"` // Buffered output (only included if requested) } // ProcessOutputChunk represents a single piece of process output (stdout or stderr). @@ -134,12 +134,12 @@ func (b *ringBuffer) snapshot() []ProcessOutputChunk { // commandProcess represents a single running background process and its state. type commandProcess struct { - info ProcessInfo // Process metadata and current status - cmd *exec.Cmd // Underlying OS process (nil after completion) - buffer *ringBuffer // Memory-bounded output storage - stopOnce sync.Once // Ensures stopSignal is only closed once - stopSignal chan struct{} // Signals output readers to exit before process termination - mu sync.Mutex // Protects info fields during updates + info ProcessInfo // Process metadata and current status + cmd *exec.Cmd // Underlying OS process (nil after completion) + buffer *ringBuffer // Memory-bounded output storage + stopOnce sync.Once // Ensures stopSignal is only closed once + stopSignal chan struct{} // Signals output readers to exit before process termination + mu sync.Mutex // Protects info fields during updates } // ProcessRunner manages multiple background processes with output streaming. @@ -147,11 +147,11 @@ type commandProcess struct { // Thread-safe: All public methods can be called concurrently from multiple goroutines. // // Process Lifecycle: -// 1. Start() creates a process in "starting" state -// 2. Transitions to "running" after successful spawn -// 3. Background goroutines stream output and wait for exit -// 4. Final status is "exited" (exit code 0) or "failed" (non-zero exit code) -// 5. Process is automatically removed from tracking after completion +// 1. Start() creates a process in "starting" state +// 2. Transitions to "running" after successful spawn +// 3. Background goroutines stream output and wait for exit +// 4. Final status is "exited" (exit code 0) or "failed" (non-zero exit code) +// 5. Process is automatically removed from tracking after completion // // Output Handling: // - Stdout and stderr are captured separately and streamed to WebSocket @@ -167,18 +167,18 @@ type ProcessRunner struct { workspaceTracker *WorkspaceTracker // WebSocket stream coordinator (can be nil) bufferMaxBytes int64 // Default output buffer size for new processes - mu sync.RWMutex // Protects processes map - processes map[string]*commandProcess // Active processes by ID + mu sync.RWMutex // Protects processes map + processes map[string]*commandProcess // Active processes by ID } // NewProcessRunner creates a new process runner. // // Parameters: // - workspaceTracker: Optional coordinator for streaming output to WebSocket clients. -// If nil, processes run but output isn't streamed (only buffered). +// If nil, processes run but output isn't streamed (only buffered). // - log: Logger instance for process lifecycle events // - bufferMaxBytes: Default output buffer size (typically 2MB). Individual processes -// can override via StartProcessRequest.BufferMaxBytes. +// can override via StartProcessRequest.BufferMaxBytes. func NewProcessRunner(workspaceTracker *WorkspaceTracker, log *logger.Logger, bufferMaxBytes int64) *ProcessRunner { return &ProcessRunner{ logger: log.WithFields(zap.String("component", "process-runner")), @@ -409,7 +409,7 @@ func (r *ProcessRunner) StopAll(ctx context.Context) error { // Parameters: // - id: Process UUID returned by Start() // - includeOutput: If true, includes buffered stdout/stderr in the response. -// Set to false for status checks to avoid copying large buffers. +// Set to false for status checks to avoid copying large buffers. // // Returns (ProcessInfo, true) if found, or (nil, false) if not found. // @@ -428,7 +428,7 @@ func (r *ProcessRunner) Get(id string, includeOutput bool) (*ProcessInfo, bool) // // Parameters: // - sessionID: If non-empty, returns only processes for this session. -// If empty, returns all processes across all sessions. +// If empty, returns all processes across all sessions. // // Output is always returned without buffered output (includeOutput=false). // Use Get(id, true) to retrieve output for a specific process. @@ -486,11 +486,11 @@ func (r *ProcessRunner) readOutput(proc *commandProcess, reader io.ReadCloser, s // wait blocks until the process exits, then updates final status and cleans up. // // This runs in a background goroutine spawned by Start(). Responsibilities: -// 1. Wait for process termination (blocks on cmd.Wait()) -// 2. Extract exit code from process state -// 3. Determine final status: "exited" (code 0) vs "failed" (non-zero) -// 4. Publish final status update to WebSocket clients -// 5. Remove process from tracking map (makes ID unavailable for future lookups) +// 1. Wait for process termination (blocks on cmd.Wait()) +// 2. Extract exit code from process state +// 3. Determine final status: "exited" (code 0) vs "failed" (non-zero) +// 4. Publish final status update to WebSocket clients +// 5. Remove process from tracking map (makes ID unavailable for future lookups) // // Exit Code Extraction: // - Success (exit code 0): Status = "exited" @@ -596,7 +596,7 @@ func (r *ProcessRunner) publishStatus(proc *commandProcess) { // // Parameters: // - includeOutput: If true, includes buffered output chunks (can be large). -// If false, returns info without output (faster, smaller). +// If false, returns info without output (faster, smaller). // // Thread-safe: Locks process mutex to prevent races with status updates. func (p *commandProcess) snapshot(includeOutput bool) ProcessInfo { @@ -612,14 +612,15 @@ func (p *commandProcess) snapshot(includeOutput bool) ProcessInfo { // mergeEnv merges custom environment variables with the parent process environment. // // Strategy: -// 1. Start with all environment variables from os.Environ() (parent process) -// 2. Override/add variables from the env map (custom variables) -// 3. Return as []string in "KEY=VALUE" format (required by exec.Cmd.Env) +// 1. Start with all environment variables from os.Environ() (parent process) +// 2. Override/add variables from the env map (custom variables) +// 3. Return as []string in "KEY=VALUE" format (required by exec.Cmd.Env) // // Example: -// Parent env: PATH=/usr/bin, HOME=/home/user -// Custom env: PATH=/custom/bin, FOO=bar -// Result: PATH=/custom/bin, HOME=/home/user, FOO=bar +// +// Parent env: PATH=/usr/bin, HOME=/home/user +// Custom env: PATH=/custom/bin, FOO=bar +// Result: PATH=/custom/bin, HOME=/home/user, FOO=bar // // This allows processes to inherit the agentctl server's environment (including PATH, // HOME, etc.) while also supporting custom variables per process. diff --git a/apps/backend/internal/agentctl/server/process/status_tracker.go b/apps/backend/internal/agentctl/server/process/status_tracker.go index 96835d5f6b..a31608ecf7 100644 --- a/apps/backend/internal/agentctl/server/process/status_tracker.go +++ b/apps/backend/internal/agentctl/server/process/status_tracker.go @@ -40,10 +40,10 @@ type StateChangeCallback func(sessionID string, state AgentState) // StatusTrackerConfig contains configuration for the status tracker. type StatusTrackerConfig struct { - Rows int // Terminal rows (default 24) - Cols int // Terminal columns (default 80) - CheckInterval time.Duration // How often to check state (default 100ms) - StabilityWindow time.Duration // Time state must be stable before reporting (default 0) + Rows int // Terminal rows (default 24) + Cols int // Terminal columns (default 80) + CheckInterval time.Duration // How often to check state (default 100ms) + StabilityWindow time.Duration // Time state must be stable before reporting (default 0) } // DefaultStatusTrackerConfig returns the default configuration. @@ -58,11 +58,11 @@ func DefaultStatusTrackerConfig() StatusTrackerConfig { // StatusTracker uses a virtual terminal emulator to track agent state. type StatusTracker struct { - logger *logger.Logger - sessionID string - detector StatusDetector - callback StateChangeCallback - config StatusTrackerConfig + logger *logger.Logger + sessionID string + detector StatusDetector + callback StateChangeCallback + config StatusTrackerConfig // vt10x terminal emulator term vt10x.Terminal @@ -72,8 +72,8 @@ type StatusTracker struct { lastState AgentState lastStateChange time.Time lastCheck time.Time - pendingState AgentState // State waiting for stability window - pendingStateTime time.Time // When pending state was first detected + pendingState AgentState // State waiting for stability window + pendingStateTime time.Time // When pending state was first detected } // NewStatusTracker creates a new status tracker with the given detector. @@ -98,13 +98,13 @@ func NewStatusTracker( term := vt10x.New(vt10x.WithSize(config.Cols, config.Rows)) return &StatusTracker{ - logger: log.WithFields(zap.String("component", "status-tracker"), zap.String("session_id", sessionID)), - sessionID: sessionID, - detector: detector, - callback: callback, - config: config, - term: term, - lastState: StateUnknown, + logger: log.WithFields(zap.String("component", "status-tracker"), zap.String("session_id", sessionID)), + sessionID: sessionID, + detector: detector, + callback: callback, + config: config, + term: term, + lastState: StateUnknown, } } diff --git a/apps/backend/internal/agentctl/server/process/status_tracker_test.go b/apps/backend/internal/agentctl/server/process/status_tracker_test.go index 2278114923..f7eeef4144 100644 --- a/apps/backend/internal/agentctl/server/process/status_tracker_test.go +++ b/apps/backend/internal/agentctl/server/process/status_tracker_test.go @@ -10,7 +10,7 @@ import ( // mockDetector is a test detector that returns configurable states type mockDetector struct { - state AgentState + state AgentState acceptTransition bool } diff --git a/apps/backend/internal/agentctl/server/shell/session_test.go b/apps/backend/internal/agentctl/server/shell/session_test.go index 899b05b92f..fde0dc990d 100644 --- a/apps/backend/internal/agentctl/server/shell/session_test.go +++ b/apps/backend/internal/agentctl/server/shell/session_test.go @@ -550,4 +550,3 @@ func TestDetectShellFallback(t *testing.T) { t.Logf("Detected shell: %q (may be valid if it exists on this system)", shell) } } - diff --git a/apps/backend/internal/agentctl/types/streams/doc.go b/apps/backend/internal/agentctl/types/streams/doc.go index f793e4b524..489e08a793 100644 --- a/apps/backend/internal/agentctl/types/streams/doc.go +++ b/apps/backend/internal/agentctl/types/streams/doc.go @@ -52,4 +52,3 @@ // // All streams use JSON-encoded messages over WebSocket connections. package streams - diff --git a/apps/backend/internal/agentctl/types/streams/permission.go b/apps/backend/internal/agentctl/types/streams/permission.go index 3e0d5c0e33..e1bf43b521 100644 --- a/apps/backend/internal/agentctl/types/streams/permission.go +++ b/apps/backend/internal/agentctl/types/streams/permission.go @@ -100,4 +100,3 @@ type PermissionRespondResponse struct { // Error contains error message if Success is false. Error string `json:"error,omitempty"` } - diff --git a/apps/backend/internal/agentctl/types/streams/shell.go b/apps/backend/internal/agentctl/types/streams/shell.go index 3364265b7f..3d3a1e46b5 100644 --- a/apps/backend/internal/agentctl/types/streams/shell.go +++ b/apps/backend/internal/agentctl/types/streams/shell.go @@ -61,4 +61,3 @@ type ShellBufferResponse struct { // Data contains the buffered shell output. Data string `json:"data"` } - diff --git a/apps/backend/internal/agentctl/types/streams/tool_payload.go b/apps/backend/internal/agentctl/types/streams/tool_payload.go index dfdbd6cac0..6fe9a95bcb 100644 --- a/apps/backend/internal/agentctl/types/streams/tool_payload.go +++ b/apps/backend/internal/agentctl/types/streams/tool_payload.go @@ -58,18 +58,18 @@ type NormalizedPayload struct { // --- Getters for NormalizedPayload --- -func (p *NormalizedPayload) Kind() ToolKind { return p.kind } -func (p *NormalizedPayload) ReadFile() *ReadFilePayload { return p.readFile } -func (p *NormalizedPayload) ModifyFile() *ModifyFilePayload { return p.modifyFile } -func (p *NormalizedPayload) ShellExec() *ShellExecPayload { return p.shellExec } -func (p *NormalizedPayload) CodeSearch() *CodeSearchPayload { return p.codeSearch } -func (p *NormalizedPayload) HttpRequest() *HttpRequestPayload { return p.httpRequest } -func (p *NormalizedPayload) Generic() *GenericPayload { return p.generic } -func (p *NormalizedPayload) CreateTask() *CreateTaskPayload { return p.createTask } +func (p *NormalizedPayload) Kind() ToolKind { return p.kind } +func (p *NormalizedPayload) ReadFile() *ReadFilePayload { return p.readFile } +func (p *NormalizedPayload) ModifyFile() *ModifyFilePayload { return p.modifyFile } +func (p *NormalizedPayload) ShellExec() *ShellExecPayload { return p.shellExec } +func (p *NormalizedPayload) CodeSearch() *CodeSearchPayload { return p.codeSearch } +func (p *NormalizedPayload) HttpRequest() *HttpRequestPayload { return p.httpRequest } +func (p *NormalizedPayload) Generic() *GenericPayload { return p.generic } +func (p *NormalizedPayload) CreateTask() *CreateTaskPayload { return p.createTask } func (p *NormalizedPayload) SubagentTask() *SubagentTaskPayload { return p.subagentTask } -func (p *NormalizedPayload) ShowPlan() *ShowPlanPayload { return p.showPlan } -func (p *NormalizedPayload) ManageTodos() *ManageTodosPayload { return p.manageTodos } -func (p *NormalizedPayload) Misc() *MiscPayload { return p.misc } +func (p *NormalizedPayload) ShowPlan() *ShowPlanPayload { return p.showPlan } +func (p *NormalizedPayload) ManageTodos() *ManageTodosPayload { return p.manageTodos } +func (p *NormalizedPayload) Misc() *MiscPayload { return p.misc } // MarshalJSON implements custom JSON marshaling for NormalizedPayload. func (p *NormalizedPayload) MarshalJSON() ([]byte, error) { diff --git a/apps/backend/internal/clarification/handlers.go b/apps/backend/internal/clarification/handlers.go index a49060d8c1..dd10240645 100644 --- a/apps/backend/internal/clarification/handlers.go +++ b/apps/backend/internal/clarification/handlers.go @@ -202,8 +202,8 @@ func (h *Handlers) httpRespond(c *gin.Context) { zap.String("pending_id", pendingID), zap.Error(err)) c.JSON(http.StatusGone, gin.H{ - "error": "clarification request expired", - "code": "CLARIFICATION_EXPIRED", + "error": "clarification request expired", + "code": "CLARIFICATION_EXPIRED", "message": "This question has timed out. The agent may have already moved on.", }) return @@ -261,4 +261,3 @@ func (h *Handlers) markRequestExpired(c *gin.Context, pendingID string) { func generateOptionID(questionIndex, optionIndex int) string { return fmt.Sprintf("q%d_opt%d", questionIndex+1, optionIndex+1) } - diff --git a/apps/backend/internal/clarification/store.go b/apps/backend/internal/clarification/store.go index 9d4234424e..284de40c03 100644 --- a/apps/backend/internal/clarification/store.go +++ b/apps/backend/internal/clarification/store.go @@ -13,9 +13,9 @@ import ( // Store manages pending clarification requests. // It provides thread-safe storage and notification when responses arrive. type Store struct { - mu sync.RWMutex - pending map[string]*PendingClarification - timeout time.Duration + mu sync.RWMutex + pending map[string]*PendingClarification + timeout time.Duration } // NewStore creates a new clarification store. @@ -131,10 +131,10 @@ func (s *Store) Cancel(pendingID string) error { // Send a cancelled response select { case pending.ResponseCh <- &Response{ - PendingID: pendingID, - Rejected: true, + PendingID: pendingID, + Rejected: true, RejectReason: "cancelled", - RespondedAt: time.Now(), + RespondedAt: time.Now(), }: default: } @@ -181,4 +181,3 @@ func (s *Store) ListPending() []*Request { } return requests } - diff --git a/apps/backend/internal/clarification/types.go b/apps/backend/internal/clarification/types.go index 92f0256271..72966dfdc3 100644 --- a/apps/backend/internal/clarification/types.go +++ b/apps/backend/internal/clarification/types.go @@ -64,4 +64,3 @@ const ( StatusExpired Status = "expired" StatusCancelled Status = "cancelled" ) - diff --git a/apps/backend/internal/common/logger/logger.go b/apps/backend/internal/common/logger/logger.go index 509850bc98..83660d7f3d 100644 --- a/apps/backend/internal/common/logger/logger.go +++ b/apps/backend/internal/common/logger/logger.go @@ -213,4 +213,3 @@ func (l *Logger) Zap() *zap.Logger { func (l *Logger) Sugar() *zap.SugaredLogger { return l.sugar } - diff --git a/apps/backend/internal/common/portutil/portutil.go b/apps/backend/internal/common/portutil/portutil.go index 4b6c73e339..7e24ded4c4 100644 --- a/apps/backend/internal/common/portutil/portutil.go +++ b/apps/backend/internal/common/portutil/portutil.go @@ -35,14 +35,15 @@ func AllocatePort() (int, error) { // Multiple occurrences of the same placeholder get the same port. // // Examples: -// Input: "npm run dev -- --port $PORT" -// Output: "npm run dev -- --port 54321", {"PORT": "54321"} // -// Input: "vite --port ${PORT}" -// Output: "vite --port 54321", {"PORT": "54321"} +// Input: "npm run dev -- --port $PORT" +// Output: "npm run dev -- --port 54321", {"PORT": "54321"} // -// Input: "npm run dev" (no placeholder) -// Output: "npm run dev", {} +// Input: "vite --port ${PORT}" +// Output: "vite --port 54321", {"PORT": "54321"} +// +// Input: "npm run dev" (no placeholder) +// Output: "npm run dev", {} func TransformCommand(command string) (string, map[string]string, error) { // Find all unique placeholder names uniquePlaceholders := findUniquePlaceholders(command) diff --git a/apps/backend/internal/debug/handlers.go b/apps/backend/internal/debug/handlers.go index 62a223928c..cdf0fae711 100644 --- a/apps/backend/internal/debug/handlers.go +++ b/apps/backend/internal/debug/handlers.go @@ -16,8 +16,8 @@ import ( func getAdapterBaseDir() (string, error) { // Try multiple possible paths candidates := []string{ - "apps/backend/internal/agentctl/server/adapter", // From git root - "internal/agentctl/server/adapter", // From apps/backend + "apps/backend/internal/agentctl/server/adapter", // From git root + "internal/agentctl/server/adapter", // From apps/backend } cwd, err := os.Getwd() diff --git a/apps/backend/internal/editors/service/service.go b/apps/backend/internal/editors/service/service.go index 38f08db7c3..fc2ab4bcb1 100644 --- a/apps/backend/internal/editors/service/service.go +++ b/apps/backend/internal/editors/service/service.go @@ -30,9 +30,9 @@ var ( // Editor kind constants for custom editor types. const ( - editorKindCustomRemoteSSH = "custom_remote_ssh" - editorKindCustomHostedURL = "custom_hosted_url" - editorKindCustomCommand = "custom_command" + editorKindCustomRemoteSSH = "custom_remote_ssh" + editorKindCustomHostedURL = "custom_hosted_url" + editorKindCustomCommand = "custom_command" ) type UserSettingsProvider interface { diff --git a/apps/backend/internal/events/bus/bus.go b/apps/backend/internal/events/bus/bus.go index 7c6007d31c..94121c550d 100644 --- a/apps/backend/internal/events/bus/bus.go +++ b/apps/backend/internal/events/bus/bus.go @@ -58,4 +58,3 @@ type EventBus interface { // IsConnected returns connection status IsConnected() bool } - diff --git a/apps/backend/internal/events/bus/memory.go b/apps/backend/internal/events/bus/memory.go index e2a5586aa5..e959623a07 100644 --- a/apps/backend/internal/events/bus/memory.go +++ b/apps/backend/internal/events/bus/memory.go @@ -24,13 +24,13 @@ type MemoryEventBus struct { // memorySubscription represents an in-memory subscription type memorySubscription struct { - bus *MemoryEventBus - subject string - pattern *regexp.Regexp // For wildcard matching - handler EventHandler - queue string // Empty for regular subscriptions - active bool - mu sync.Mutex + bus *MemoryEventBus + subject string + pattern *regexp.Regexp // For wildcard matching + handler EventHandler + queue string // Empty for regular subscriptions + active bool + mu sync.Mutex } // queueGroup manages load balancing for queue subscriptions diff --git a/apps/backend/internal/events/bus/nats.go b/apps/backend/internal/events/bus/nats.go index 9d444c3dc7..bd9d965dee 100644 --- a/apps/backend/internal/events/bus/nats.go +++ b/apps/backend/internal/events/bus/nats.go @@ -189,4 +189,3 @@ func (b *NATSEventBus) IsConnected() bool { } return b.conn.IsConnected() } - diff --git a/apps/backend/internal/events/bus/subscription.go b/apps/backend/internal/events/bus/subscription.go index ee74eed718..e7fb84e782 100644 --- a/apps/backend/internal/events/bus/subscription.go +++ b/apps/backend/internal/events/bus/subscription.go @@ -22,4 +22,3 @@ func (s *natsSubscription) IsValid() bool { } return s.sub.IsValid() } - diff --git a/apps/backend/internal/events/types.go b/apps/backend/internal/events/types.go index 651222e522..de17720197 100644 --- a/apps/backend/internal/events/types.go +++ b/apps/backend/internal/events/types.go @@ -248,4 +248,3 @@ func BuildAvailableCommandsSubject(sessionID string) string { func BuildAvailableCommandsWildcardSubject() string { return AvailableCommandsUpdated + ".*" } - diff --git a/apps/backend/internal/gateway/websocket/handler.go b/apps/backend/internal/gateway/websocket/handler.go index 1e49eabc45..37147882e0 100644 --- a/apps/backend/internal/gateway/websocket/handler.go +++ b/apps/backend/internal/gateway/websocket/handler.go @@ -72,8 +72,6 @@ func (h *Handler) HandleConnection(c *gin.Context) { client.ReadPump(c.Request.Context()) } - - // RegisterHealthHandler registers the health check handler func RegisterHealthHandler(d *ws.Dispatcher) { d.RegisterFunc(ws.ActionHealthCheck, func(ctx context.Context, msg *ws.Message) (*ws.Message, error) { @@ -84,4 +82,3 @@ func RegisterHealthHandler(d *ws.Dispatcher) { }) }) } - diff --git a/apps/backend/internal/gateway/websocket/hub.go b/apps/backend/internal/gateway/websocket/hub.go index df3697790a..e654bd6974 100644 --- a/apps/backend/internal/gateway/websocket/hub.go +++ b/apps/backend/internal/gateway/websocket/hub.go @@ -355,4 +355,4 @@ func (h *Hub) GetSessionData(ctx context.Context, sessionID string) ([]*ws.Messa return nil, nil } return h.sessionDataProvider(ctx, sessionID) -} \ No newline at end of file +} diff --git a/apps/backend/internal/gateway/websocket/session_notifications.go b/apps/backend/internal/gateway/websocket/session_notifications.go index 9d615d0274..a53313afae 100644 --- a/apps/backend/internal/gateway/websocket/session_notifications.go +++ b/apps/backend/internal/gateway/websocket/session_notifications.go @@ -25,8 +25,8 @@ type SessionStreamBroadcaster struct { // File change debouncing fileChangeMu sync.Mutex - fileChangeBatch map[string][]any // sessionID -> list of file change payloads - fileChangeTimers map[string]*time.Timer // sessionID -> debounce timer + fileChangeBatch map[string][]any // sessionID -> list of file change payloads + fileChangeTimers map[string]*time.Timer // sessionID -> debounce timer } func RegisterSessionStreamNotifications(ctx context.Context, eventBus bus.EventBus, hub *Hub, log *logger.Logger) *SessionStreamBroadcaster { diff --git a/apps/backend/internal/gateway/websocket/setup.go b/apps/backend/internal/gateway/websocket/setup.go index 011eff57be..aa41245d58 100644 --- a/apps/backend/internal/gateway/websocket/setup.go +++ b/apps/backend/internal/gateway/websocket/setup.go @@ -62,4 +62,3 @@ func (g *Gateway) SetupRoutes(router *gin.Engine) { router.GET("/lsp/:sessionId", g.LSPHandler.HandleLSPConnection) } } - diff --git a/apps/backend/internal/notifications/providers/system_provider.go b/apps/backend/internal/notifications/providers/system_provider.go index 80b0b5823c..092194d33e 100644 --- a/apps/backend/internal/notifications/providers/system_provider.go +++ b/apps/backend/internal/notifications/providers/system_provider.go @@ -11,13 +11,13 @@ import ( "time" ) - // OS name constants used for runtime.GOOS comparisons. const ( osDarwin = "darwin" osLinux = "linux" osWindows = "windows" ) + type SystemProvider struct { assets systemAssets } diff --git a/apps/backend/internal/notifications/service/service.go b/apps/backend/internal/notifications/service/service.go index 99369253c7..a7c924a765 100644 --- a/apps/backend/internal/notifications/service/service.go +++ b/apps/backend/internal/notifications/service/service.go @@ -281,10 +281,10 @@ func (s *Service) ensureSystemProvider(ctx context.Context, userID string) error return nil } provider := &models.Provider{ - ID: uuid.New().String(), - UserID: userID, - Name: "System Notifications", - Type: models.ProviderTypeSystem, + ID: uuid.New().String(), + UserID: userID, + Name: "System Notifications", + Type: models.ProviderTypeSystem, Config: map[string]interface{}{ "sound_enabled": false, }, diff --git a/apps/backend/internal/orchestrator/event_handlers_streaming.go b/apps/backend/internal/orchestrator/event_handlers_streaming.go index 8c49591f83..1334482f8f 100644 --- a/apps/backend/internal/orchestrator/event_handlers_streaming.go +++ b/apps/backend/internal/orchestrator/event_handlers_streaming.go @@ -299,10 +299,10 @@ func (s *Service) handleToolUpdateEvent(ctx context.Context, payload *lifecycle. payload.Data.ToolStatus, "", // result - no longer used, tool results in NormalizedPayload payload.SessionID, - payload.Data.ToolTitle, // Include title from update event + payload.Data.ToolTitle, // Include title from update event s.getActiveTurnID(payload.SessionID), // Turn ID for fallback creation - msgType, // Message type for fallback creation - payload.Data.Normalized, // Pass normalized tool data for message metadata + msgType, // Message type for fallback creation + payload.Data.Normalized, // Pass normalized tool data for message metadata ); err != nil { s.logger.Warn("failed to update tool call message", zap.String("task_id", payload.TaskID), diff --git a/apps/backend/internal/orchestrator/event_handlers_test.go b/apps/backend/internal/orchestrator/event_handlers_test.go index 324505279f..ca87dbf357 100644 --- a/apps/backend/internal/orchestrator/event_handlers_test.go +++ b/apps/backend/internal/orchestrator/event_handlers_test.go @@ -9,8 +9,8 @@ import ( "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" - "github.com/kandev/kandev/internal/db" "github.com/kandev/kandev/internal/common/logger" + "github.com/kandev/kandev/internal/db" "github.com/kandev/kandev/internal/orchestrator/executor" "github.com/kandev/kandev/internal/task/models" "github.com/kandev/kandev/internal/task/repository" @@ -738,4 +738,3 @@ func TestProcessOnEnterPassthrough(t *testing.T) { } }) } - diff --git a/apps/backend/internal/orchestrator/executor/executor.go b/apps/backend/internal/orchestrator/executor/executor.go index b172cd6661..8b71dcb71a 100644 --- a/apps/backend/internal/orchestrator/executor/executor.go +++ b/apps/backend/internal/orchestrator/executor/executor.go @@ -93,8 +93,8 @@ type LaunchAgentRequest struct { Priority int Metadata map[string]interface{} Env map[string]string - ACPSessionID string // ACP session ID to resume, if available - ModelOverride string // If set, use this model instead of the profile's model + ACPSessionID string // ACP session ID to resume, if available + ModelOverride string // If set, use this model instead of the profile's model ExecutorType string // Executor type (e.g., "local", "worktree", "local_docker") - determines runtime ExecutorConfig map[string]string // Executor config (docker_host, git_token, etc.) @@ -209,4 +209,3 @@ func NewExecutor(agentManager AgentManagerClient, repo repository.Repository, lo func (e *Executor) SetOnTaskStateChange(fn TaskStateChangeFunc) { e.onTaskStateChange = fn } - diff --git a/apps/backend/internal/orchestrator/executor/executor_test.go b/apps/backend/internal/orchestrator/executor/executor_test.go index fc3a3dc567..f417aac01b 100644 --- a/apps/backend/internal/orchestrator/executor/executor_test.go +++ b/apps/backend/internal/orchestrator/executor/executor_test.go @@ -13,10 +13,10 @@ import ( // mockAgentManager implements AgentManagerClient for testing type mockAgentManager struct { - launchAgentFunc func(ctx context.Context, req *LaunchAgentRequest) (*LaunchAgentResponse, error) - startAgentProcessFunc func(ctx context.Context, agentExecutionID string) error - resolveAgentProfileFunc func(ctx context.Context, profileID string) (*AgentProfileInfo, error) - setExecutionDescriptionFunc func(ctx context.Context, agentExecutionID string, description string) error + launchAgentFunc func(ctx context.Context, req *LaunchAgentRequest) (*LaunchAgentResponse, error) + startAgentProcessFunc func(ctx context.Context, agentExecutionID string) error + resolveAgentProfileFunc func(ctx context.Context, profileID string) (*AgentProfileInfo, error) + setExecutionDescriptionFunc func(ctx context.Context, agentExecutionID string, description string) error } func (m *mockAgentManager) LaunchAgent(ctx context.Context, req *LaunchAgentRequest) (*LaunchAgentResponse, error) { @@ -287,7 +287,7 @@ func (m *mockRepository) GetActiveTurnBySessionID(ctx context.Context, sessionID return nil, nil } func (m *mockRepository) UpdateTurn(ctx context.Context, turn *models.Turn) error { return nil } -func (m *mockRepository) CompleteTurn(ctx context.Context, id string) error { return nil } +func (m *mockRepository) CompleteTurn(ctx context.Context, id string) error { return nil } func (m *mockRepository) CompleteRunningToolCallsForTurn(ctx context.Context, turnID string) (int64, error) { return 0, nil } @@ -882,9 +882,9 @@ func TestShouldUseWorktree(t *testing.T) { func TestRepositoryCloneURL(t *testing.T) { tests := []struct { - name string - repo *models.Repository - want string + name string + repo *models.Repository + want string }{ { name: "github repo", diff --git a/apps/backend/internal/orchestrator/handlers/queue_handlers.go b/apps/backend/internal/orchestrator/handlers/queue_handlers.go index 7bfb4d4bd2..a59661c856 100644 --- a/apps/backend/internal/orchestrator/handlers/queue_handlers.go +++ b/apps/backend/internal/orchestrator/handlers/queue_handlers.go @@ -46,13 +46,13 @@ func (h *QueueHandlers) RegisterHandlers(d *ws.Dispatcher) { // WebSocket Handlers type wsQueueMessageRequest struct { - SessionID string `json:"session_id"` - TaskID string `json:"task_id"` - Content string `json:"content"` - Model string `json:"model,omitempty"` - PlanMode bool `json:"plan_mode,omitempty"` + SessionID string `json:"session_id"` + TaskID string `json:"task_id"` + Content string `json:"content"` + Model string `json:"model,omitempty"` + PlanMode bool `json:"plan_mode,omitempty"` Attachments []messagequeue.MessageAttachment `json:"attachments,omitempty"` - UserID string `json:"user_id,omitempty"` + UserID string `json:"user_id,omitempty"` } func (h *QueueHandlers) wsQueueMessage(ctx context.Context, msg *ws.Message) (*ws.Message, error) { diff --git a/apps/backend/internal/orchestrator/handlers/queue_handlers_test.go b/apps/backend/internal/orchestrator/handlers/queue_handlers_test.go index cf5c538d77..648df69d54 100644 --- a/apps/backend/internal/orchestrator/handlers/queue_handlers_test.go +++ b/apps/backend/internal/orchestrator/handlers/queue_handlers_test.go @@ -17,10 +17,10 @@ import ( // mockQueueService is a simple mock implementation of QueueService type mockQueueService struct { - queueMessageFunc func(ctx context.Context, sessionID, taskID, content, model, userID string, planMode bool, attachments []messagequeue.MessageAttachment) (*messagequeue.QueuedMessage, error) - cancelQueuedFunc func(ctx context.Context, sessionID string) (*messagequeue.QueuedMessage, error) - getStatusFunc func(ctx context.Context, sessionID string) *messagequeue.QueueStatus - updateMessageFunc func(ctx context.Context, sessionID, content string) error + queueMessageFunc func(ctx context.Context, sessionID, taskID, content, model, userID string, planMode bool, attachments []messagequeue.MessageAttachment) (*messagequeue.QueuedMessage, error) + cancelQueuedFunc func(ctx context.Context, sessionID string) (*messagequeue.QueuedMessage, error) + getStatusFunc func(ctx context.Context, sessionID string) *messagequeue.QueueStatus + updateMessageFunc func(ctx context.Context, sessionID, content string) error } func (m *mockQueueService) QueueMessage(ctx context.Context, sessionID, taskID, content, model, userID string, planMode bool, attachments []messagequeue.MessageAttachment) (*messagequeue.QueuedMessage, error) { diff --git a/apps/backend/internal/orchestrator/messagequeue/types.go b/apps/backend/internal/orchestrator/messagequeue/types.go index ad8845ba91..b5437d9031 100644 --- a/apps/backend/internal/orchestrator/messagequeue/types.go +++ b/apps/backend/internal/orchestrator/messagequeue/types.go @@ -4,15 +4,15 @@ import "time" // QueuedMessage represents a message queued for a session type QueuedMessage struct { - ID string `json:"id"` // Unique queue entry ID - SessionID string `json:"session_id"` // Task session ID - TaskID string `json:"task_id"` // Task ID - Content string `json:"content"` // Message content - Model string `json:"model"` // Optional model override - PlanMode bool `json:"plan_mode"` // Plan mode enabled - Attachments []MessageAttachment `json:"attachments"` // Image attachments - QueuedAt time.Time `json:"queued_at"` // When queued - QueuedBy string `json:"queued_by"` // User ID who queued + ID string `json:"id"` // Unique queue entry ID + SessionID string `json:"session_id"` // Task session ID + TaskID string `json:"task_id"` // Task ID + Content string `json:"content"` // Message content + Model string `json:"model"` // Optional model override + PlanMode bool `json:"plan_mode"` // Plan mode enabled + Attachments []MessageAttachment `json:"attachments"` // Image attachments + QueuedAt time.Time `json:"queued_at"` // When queued + QueuedBy string `json:"queued_by"` // User ID who queued } // MessageAttachment represents an attachment (image) in a queued message @@ -24,6 +24,6 @@ type MessageAttachment struct { // QueueStatus represents the queue status for a session type QueueStatus struct { - IsQueued bool `json:"is_queued"` // Whether a message is queued - Message *QueuedMessage `json:"message"` // The queued message (nil if not queued) + IsQueued bool `json:"is_queued"` // Whether a message is queued + Message *QueuedMessage `json:"message"` // The queued message (nil if not queued) } diff --git a/apps/backend/internal/orchestrator/queue/queue.go b/apps/backend/internal/orchestrator/queue/queue.go index 7819564da1..b44db9034f 100644 --- a/apps/backend/internal/orchestrator/queue/queue.go +++ b/apps/backend/internal/orchestrator/queue/queue.go @@ -18,11 +18,11 @@ var ( // QueuedTask represents a task in the priority queue type QueuedTask struct { - TaskID string - Priority int // Higher priority = processed first - QueuedAt time.Time - Task *v1.Task // Full task data - index int // Index in the heap (used by container/heap) + TaskID string + Priority int // Higher priority = processed first + QueuedAt time.Time + Task *v1.Task // Full task data + index int // Index in the heap (used by container/heap) } // taskHeap implements heap.Interface for priority queue @@ -95,10 +95,10 @@ func (q *TaskQueue) Enqueue(task *v1.Task) error { } qt := &QueuedTask{ - TaskID: task.ID, - Priority: task.Priority, - QueuedAt: time.Now(), - Task: task, + TaskID: task.ID, + Priority: task.Priority, + QueuedAt: time.Now(), + Task: task, } heap.Push(&q.heap, qt) diff --git a/apps/backend/internal/orchestrator/queue/queue_test.go b/apps/backend/internal/orchestrator/queue/queue_test.go index c666ecc316..d37ff6c849 100644 --- a/apps/backend/internal/orchestrator/queue/queue_test.go +++ b/apps/backend/internal/orchestrator/queue/queue_test.go @@ -11,13 +11,13 @@ import ( // createTestTask creates a task for testing with the given parameters func createTestTask(id string, priority int) *v1.Task { return &v1.Task{ - ID: id, + ID: id, WorkflowID: "test-wf", - Title: "Test Task " + id, - Priority: priority, - State: v1.TaskStateTODO, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), + Title: "Test Task " + id, + Priority: priority, + State: v1.TaskStateTODO, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), } } diff --git a/apps/backend/internal/orchestrator/scheduler/scheduler_test.go b/apps/backend/internal/orchestrator/scheduler/scheduler_test.go index a06cacd72d..8d58f63087 100644 --- a/apps/backend/internal/orchestrator/scheduler/scheduler_test.go +++ b/apps/backend/internal/orchestrator/scheduler/scheduler_test.go @@ -160,13 +160,13 @@ func createTestExecutor(t *testing.T, agentMgr *mockAgentManager, log *logger.Lo func createTestTask(id string, priority int) *v1.Task { return &v1.Task{ - ID: id, + ID: id, WorkflowID: "test-wf", - Title: "Test Task " + id, - Priority: priority, - State: v1.TaskStateTODO, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), + Title: "Test Task " + id, + Priority: priority, + State: v1.TaskStateTODO, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), } } diff --git a/apps/backend/internal/orchestrator/service.go b/apps/backend/internal/orchestrator/service.go index 915777cec6..4cccf89233 100644 --- a/apps/backend/internal/orchestrator/service.go +++ b/apps/backend/internal/orchestrator/service.go @@ -430,26 +430,27 @@ func (s *Service) Stop() error { // Recovery Strategy: // // 1. Query database for sessions marked as "running" (persisted executor state) +// // 2. For each session, determine recovery action based on previous state: // // Terminal States (Completed/Failed/Cancelled): -// - Clean up stale executor record from database -// - Skip resume (session is already done) +// - Clean up stale executor record from database +// - Skip resume (session is already done) // // Never-Started State (Created): -// - Clean up executor record (session never actually ran) -// - Skip resume (nothing to recover) +// - Clean up executor record (session never actually ran) +// - Skip resume (nothing to recover) // // Active States (Starting/Running/WaitingForInput): -// - Validate workspace/worktree still exists -// - Launch new agentctl instance -// - Restore session via ACP session/load (if resumable) -// - Transition to WaitingForInput (ready for next prompt) +// - Validate workspace/worktree still exists +// - Launch new agentctl instance +// - Restore session via ACP session/load (if resumable) +// - Transition to WaitingForInput (ready for next prompt) // // 3. Handle resume failures gracefully: -// - Mark session as Failed in database -// - Clean up executor record -// - Continue with next session (don't block other recoveries) +// - Mark session as Failed in database +// - Clean up executor record +// - Continue with next session (don't block other recoveries) // // Agent Resume Behavior: // diff --git a/apps/backend/internal/orchestrator/task_operations.go b/apps/backend/internal/orchestrator/task_operations.go index 74a9ccbd3d..5201057c85 100644 --- a/apps/backend/internal/orchestrator/task_operations.go +++ b/apps/backend/internal/orchestrator/task_operations.go @@ -884,4 +884,3 @@ func (s *Service) CompleteTask(ctx context.Context, taskID string) error { func (s *Service) GetQueuedTasks() []*queue.QueuedTask { return s.queue.List() } - diff --git a/apps/backend/internal/orchestrator/watcher/watcher_test.go b/apps/backend/internal/orchestrator/watcher/watcher_test.go index 458253fa94..21c1d2988f 100644 --- a/apps/backend/internal/orchestrator/watcher/watcher_test.go +++ b/apps/backend/internal/orchestrator/watcher/watcher_test.go @@ -37,11 +37,11 @@ func (s *mockSubscription) IsValid() bool { // mockEventBus implements bus.EventBus for testing type mockEventBus struct { - subscriptions map[string][]bus.EventHandler - queuedSubs map[string]map[string][]bus.EventHandler - mu sync.RWMutex - connected bool - subscribeErr error + subscriptions map[string][]bus.EventHandler + queuedSubs map[string]map[string][]bus.EventHandler + mu sync.RWMutex + connected bool + subscribeErr error queueSubscribeErr error } diff --git a/apps/backend/internal/task/dto/requests.go b/apps/backend/internal/task/dto/requests.go index 704b3b4f63..2edf583f96 100644 --- a/apps/backend/internal/task/dto/requests.go +++ b/apps/backend/internal/task/dto/requests.go @@ -261,8 +261,8 @@ type CreateTaskRequest struct { Priority int State *v1.TaskState Repositories []TaskRepositoryInput - Position int - Metadata map[string]interface{} + Position int + Metadata map[string]interface{} } type UpdateTaskRequest struct { diff --git a/apps/backend/internal/task/handlers/process_handlers.go b/apps/backend/internal/task/handlers/process_handlers.go index a48d38da1b..5718885770 100644 --- a/apps/backend/internal/task/handlers/process_handlers.go +++ b/apps/backend/internal/task/handlers/process_handlers.go @@ -22,7 +22,6 @@ import ( "github.com/kandev/kandev/internal/task/service" ) - // queryValueTrue is the string "true" used in query parameter comparisons. const queryValueTrue = "true" diff --git a/apps/backend/internal/task/handlers/task_http_handlers.go b/apps/backend/internal/task/handlers/task_http_handlers.go index 2b4901f495..3186a3a07a 100644 --- a/apps/backend/internal/task/handlers/task_http_handlers.go +++ b/apps/backend/internal/task/handlers/task_http_handlers.go @@ -392,7 +392,7 @@ func (h *TaskHandlers) startAgentForNewTask( // Launch agent asynchronously so the HTTP request can return immediately. // The frontend will receive WebSocket updates when the agent actually starts. executorID := body.ExecutorID // Capture for goroutine - stepID := resolvedStepID // Capture for goroutine + stepID := resolvedStepID // Capture for goroutine go func() { // Use a longer timeout to accommodate setup scripts (which can take minutes for npm install, etc.) startCtx, cancel := context.WithTimeout(context.Background(), constants.AgentLaunchTimeout) diff --git a/apps/backend/internal/task/handlers/workflow_handlers.go b/apps/backend/internal/task/handlers/workflow_handlers.go index bdb24d91b4..8e464ba088 100644 --- a/apps/backend/internal/task/handlers/workflow_handlers.go +++ b/apps/backend/internal/task/handlers/workflow_handlers.go @@ -207,8 +207,8 @@ func (h *WorkflowHandlers) httpGetWorkflowSnapshot(c *gin.Context) { c.JSON(http.StatusOK, dto.WorkflowSnapshotDTO{ Workflow: dto.FromWorkflow(workflow), - Steps: steps, - Tasks: taskDTOs, + Steps: steps, + Tasks: taskDTOs, }) } @@ -267,8 +267,8 @@ func (h *WorkflowHandlers) httpGetWorkspaceSnapshot(c *gin.Context) { c.JSON(http.StatusOK, dto.WorkflowSnapshotDTO{ Workflow: dto.FromWorkflow(workflow), - Steps: steps, - Tasks: taskDTOs, + Steps: steps, + Tasks: taskDTOs, }) } diff --git a/apps/backend/internal/task/models/git.go b/apps/backend/internal/task/models/git.go index 13363afefe..2ee0c4bcee 100644 --- a/apps/backend/internal/task/models/git.go +++ b/apps/backend/internal/task/models/git.go @@ -61,4 +61,3 @@ type CumulativeDiff struct { TotalCommits int `json:"total_commits"` Files map[string]interface{} `json:"files"` // Cumulative file changes } - diff --git a/apps/backend/internal/task/models/models.go b/apps/backend/internal/task/models/models.go index fab9ac85b7..7a7de9b002 100644 --- a/apps/backend/internal/task/models/models.go +++ b/apps/backend/internal/task/models/models.go @@ -319,9 +319,9 @@ type RepositoryScript struct { type ExecutorType string const ( - ExecutorTypeLocal ExecutorType = "local" - ExecutorTypeWorktree ExecutorType = "worktree" - ExecutorTypeLocalDocker ExecutorType = "local_docker" + ExecutorTypeLocal ExecutorType = "local" + ExecutorTypeWorktree ExecutorType = "worktree" + ExecutorTypeLocalDocker ExecutorType = "local_docker" ExecutorTypeRemoteDocker ExecutorType = "remote_docker" ) diff --git a/apps/backend/internal/task/models/models_test.go b/apps/backend/internal/task/models/models_test.go index 66c24ba464..e653711abd 100644 --- a/apps/backend/internal/task/models/models_test.go +++ b/apps/backend/internal/task/models/models_test.go @@ -137,10 +137,10 @@ func TestTaskToAPI(t *testing.T) { WorkspaceID: "workspace-001", WorkflowID: "workflow-456", WorkflowStepID: "step-789", - Title: "Test Task", - Description: "A test task description", - State: v1.TaskStateInProgress, - Priority: 3, + Title: "Test Task", + Description: "A test task description", + State: v1.TaskStateInProgress, + Priority: 3, Repositories: []*TaskRepository{ { ID: "task-repo-1", @@ -203,14 +203,14 @@ func TestTaskToAPIWithEmptyOptionalFields(t *testing.T) { WorkspaceID: "workspace-001", WorkflowID: "workflow-456", WorkflowStepID: "step-789", - Title: "Test Task", - Description: "A test task description", - State: v1.TaskStateTODO, - Priority: 0, - Position: 0, - Metadata: nil, - CreatedAt: now, - UpdatedAt: now, + Title: "Test Task", + Description: "A test task description", + State: v1.TaskStateTODO, + Priority: 0, + Position: 0, + Metadata: nil, + CreatedAt: now, + UpdatedAt: now, } apiTask := task.ToAPI() diff --git a/apps/backend/internal/task/repository/sqlite/base.go b/apps/backend/internal/task/repository/sqlite/base.go index e8d81265b1..5db808a450 100644 --- a/apps/backend/internal/task/repository/sqlite/base.go +++ b/apps/backend/internal/task/repository/sqlite/base.go @@ -440,4 +440,3 @@ func (r *Repository) initReviewSchema() error { `) return err } - diff --git a/apps/backend/internal/task/repository/sqlite/defaults.go b/apps/backend/internal/task/repository/sqlite/defaults.go index 690f715c39..a7fb840ece 100644 --- a/apps/backend/internal/task/repository/sqlite/defaults.go +++ b/apps/backend/internal/task/repository/sqlite/defaults.go @@ -197,4 +197,3 @@ func (r *Repository) updateDefaultEnvironment(ctx context.Context) error { `), "~/kandev", models.EnvironmentIDLocal) return err } - diff --git a/apps/backend/internal/task/repository/sqlite/environment.go b/apps/backend/internal/task/repository/sqlite/environment.go index 2c3ff0103c..a2cf5f935c 100644 --- a/apps/backend/internal/task/repository/sqlite/environment.go +++ b/apps/backend/internal/task/repository/sqlite/environment.go @@ -135,4 +135,3 @@ func (r *Repository) ListEnvironments(ctx context.Context) ([]*models.Environmen } return result, rows.Err() } - diff --git a/apps/backend/internal/task/repository/sqlite/executor.go b/apps/backend/internal/task/repository/sqlite/executor.go index 5544f3ed4b..0bda8c6f48 100644 --- a/apps/backend/internal/task/repository/sqlite/executor.go +++ b/apps/backend/internal/task/repository/sqlite/executor.go @@ -325,4 +325,3 @@ func (r *Repository) HasActiveTaskSessionsByExecutor(ctx context.Context, execut } return err == nil, err } - diff --git a/apps/backend/internal/task/repository/sqlite/message.go b/apps/backend/internal/task/repository/sqlite/message.go index c9605fc5c3..69a5003dda 100644 --- a/apps/backend/internal/task/repository/sqlite/message.go +++ b/apps/backend/internal/task/repository/sqlite/message.go @@ -341,4 +341,3 @@ func (r *Repository) UpdateMessage(ctx context.Context, message *models.Message) } return nil } - diff --git a/apps/backend/internal/task/repository/sqlite/plan.go b/apps/backend/internal/task/repository/sqlite/plan.go index 59398af214..c528081c4d 100644 --- a/apps/backend/internal/task/repository/sqlite/plan.go +++ b/apps/backend/internal/task/repository/sqlite/plan.go @@ -82,4 +82,3 @@ func (r *Repository) DeleteTaskPlan(ctx context.Context, taskID string) error { } return nil } - diff --git a/apps/backend/internal/task/repository/sqlite/task.go b/apps/backend/internal/task/repository/sqlite/task.go index ec13a57bec..1d77c5feb5 100644 --- a/apps/backend/internal/task/repository/sqlite/task.go +++ b/apps/backend/internal/task/repository/sqlite/task.go @@ -341,4 +341,3 @@ func (r *Repository) UpdateTaskState(ctx context.Context, id string, state v1.Ta } return nil } - diff --git a/apps/backend/internal/task/repository/sqlite/task_repository.go b/apps/backend/internal/task/repository/sqlite/task_repository.go index efc99a5781..fb4400b21e 100644 --- a/apps/backend/internal/task/repository/sqlite/task_repository.go +++ b/apps/backend/internal/task/repository/sqlite/task_repository.go @@ -148,7 +148,6 @@ func (r *Repository) DeleteTaskRepositoriesByTask(ctx context.Context, taskID st return err } - // GetPrimaryTaskRepository returns the first (primary) repository for a task func (r *Repository) GetPrimaryTaskRepository(ctx context.Context, taskID string) (*models.TaskRepository, error) { repos, err := r.ListTaskRepositories(ctx, taskID) @@ -160,4 +159,3 @@ func (r *Repository) GetPrimaryTaskRepository(ctx context.Context, taskID string } return repos[0], nil } - diff --git a/apps/backend/internal/task/repository/sqlite/workspace.go b/apps/backend/internal/task/repository/sqlite/workspace.go index cee8a77e1a..9b29f72b92 100644 --- a/apps/backend/internal/task/repository/sqlite/workspace.go +++ b/apps/backend/internal/task/repository/sqlite/workspace.go @@ -157,4 +157,3 @@ func (r *Repository) ListWorkspaces(ctx context.Context) ([]*models.Workspace, e } return result, rows.Err() } - diff --git a/apps/backend/internal/task/repository/task_repository_test.go b/apps/backend/internal/task/repository/task_repository_test.go index c33115ff03..eef00fe305 100644 --- a/apps/backend/internal/task/repository/task_repository_test.go +++ b/apps/backend/internal/task/repository/task_repository_test.go @@ -27,7 +27,7 @@ func TestSQLiteRepository_TaskCRUD(t *testing.T) { // Create task (workflow steps are managed by workflow repository) task := &models.Task{ WorkspaceID: "ws-1", - WorkflowID: "wf-123", + WorkflowID: "wf-123", WorkflowStepID: "step-123", Title: "Test Task", Description: "A test task", @@ -196,7 +196,7 @@ func TestSQLiteRepository_ListTasksByWorkspace(t *testing.T) { _ = repo.CreateTask(ctx, &models.Task{ID: "task-4", WorkspaceID: "ws-2", WorkflowID: "wf-456", WorkflowStepID: "step-2", Title: "Task Four"}) // Test basic listing without search - tasks, total, err := repo.ListTasksByWorkspace(ctx,"ws-1", "", 1, 10, false) + tasks, total, err := repo.ListTasksByWorkspace(ctx, "ws-1", "", 1, 10, false) if err != nil { t.Fatalf("failed to list tasks by workspace: %v", err) } @@ -208,7 +208,7 @@ func TestSQLiteRepository_ListTasksByWorkspace(t *testing.T) { } // Test pagination - tasks, total, err = repo.ListTasksByWorkspace(ctx,"ws-1", "", 1, 2, false) + tasks, total, err = repo.ListTasksByWorkspace(ctx, "ws-1", "", 1, 2, false) if err != nil { t.Fatalf("failed to list tasks with pagination: %v", err) } @@ -220,7 +220,7 @@ func TestSQLiteRepository_ListTasksByWorkspace(t *testing.T) { } // Test page 2 - tasksPage2, _, err := repo.ListTasksByWorkspace(ctx,"ws-1", "", 2, 2, false) + tasksPage2, _, err := repo.ListTasksByWorkspace(ctx, "ws-1", "", 2, 2, false) if err != nil { t.Fatalf("failed to list tasks page 2: %v", err) } @@ -250,7 +250,7 @@ func TestSQLiteRepository_ListTasksByWorkspaceWithSearch(t *testing.T) { _ = repo.CreateTaskRepository(ctx, &models.TaskRepository{ID: "tr-1", TaskID: "task-1", RepositoryID: "repo-1", BaseBranch: "main"}) // Test search by title - _, totalAuth, err := repo.ListTasksByWorkspace(ctx,"ws-1", "authentication", 1, 10, false) + _, totalAuth, err := repo.ListTasksByWorkspace(ctx, "ws-1", "authentication", 1, 10, false) if err != nil { t.Fatalf("failed to search tasks by title: %v", err) } @@ -259,7 +259,7 @@ func TestSQLiteRepository_ListTasksByWorkspaceWithSearch(t *testing.T) { } // Test search by description - tasksDarkMode, totalDarkMode, err := repo.ListTasksByWorkspace(ctx,"ws-1", "dark mode", 1, 10, false) + tasksDarkMode, totalDarkMode, err := repo.ListTasksByWorkspace(ctx, "ws-1", "dark mode", 1, 10, false) if err != nil { t.Fatalf("failed to search tasks by description: %v", err) } @@ -271,7 +271,7 @@ func TestSQLiteRepository_ListTasksByWorkspaceWithSearch(t *testing.T) { } // Test search by repository name - tasksRepo, totalRepo, err := repo.ListTasksByWorkspace(ctx,"ws-1", "MyProject", 1, 10, false) + tasksRepo, totalRepo, err := repo.ListTasksByWorkspace(ctx, "ws-1", "MyProject", 1, 10, false) if err != nil { t.Fatalf("failed to search tasks by repository name: %v", err) } @@ -283,7 +283,7 @@ func TestSQLiteRepository_ListTasksByWorkspaceWithSearch(t *testing.T) { } // Test search by repository local_path - _, totalPath, err := repo.ListTasksByWorkspace(ctx,"ws-1", "myproject", 1, 10, false) + _, totalPath, err := repo.ListTasksByWorkspace(ctx, "ws-1", "myproject", 1, 10, false) if err != nil { t.Fatalf("failed to search tasks by repository path: %v", err) } @@ -292,7 +292,7 @@ func TestSQLiteRepository_ListTasksByWorkspaceWithSearch(t *testing.T) { } // Test search with no results - tasksNone, totalNone, err := repo.ListTasksByWorkspace(ctx,"ws-1", "nonexistent", 1, 10, false) + tasksNone, totalNone, err := repo.ListTasksByWorkspace(ctx, "ws-1", "nonexistent", 1, 10, false) if err != nil { t.Fatalf("failed to search tasks with no results: %v", err) } diff --git a/apps/backend/internal/task/service/plan_service.go b/apps/backend/internal/task/service/plan_service.go index 10c7562ca9..17cd864bf3 100644 --- a/apps/backend/internal/task/service/plan_service.go +++ b/apps/backend/internal/task/service/plan_service.go @@ -195,4 +195,3 @@ func (s *PlanService) publishEvent(ctx context.Context, eventType string, plan * s.logger.Error("failed to publish task plan event", zap.String("event_type", eventType), zap.Error(err)) } } - diff --git a/apps/backend/internal/task/service/service.go b/apps/backend/internal/task/service/service.go index 485d28a4fe..9e4c18c345 100644 --- a/apps/backend/internal/task/service/service.go +++ b/apps/backend/internal/task/service/service.go @@ -10,8 +10,8 @@ import ( "github.com/kandev/kandev/internal/common/logger" "github.com/kandev/kandev/internal/events/bus" "github.com/kandev/kandev/internal/task/repository" - "github.com/kandev/kandev/internal/worktree" wfmodels "github.com/kandev/kandev/internal/workflow/models" + "github.com/kandev/kandev/internal/worktree" ) // WorktreeCleanup provides worktree cleanup on task deletion. diff --git a/apps/backend/internal/task/service/service_test.go b/apps/backend/internal/task/service/service_test.go index 3fde3280e6..2c84a514ab 100644 --- a/apps/backend/internal/task/service/service_test.go +++ b/apps/backend/internal/task/service/service_test.go @@ -116,11 +116,11 @@ func TestService_CreateTask(t *testing.T) { req := &CreateTaskRequest{ WorkspaceID: "ws-1", - WorkflowID: "wf-123", + WorkflowID: "wf-123", WorkflowStepID: "step-123", - Title: "Test Task", - Description: "A test task", - Priority: 5, + Title: "Test Task", + Description: "A test task", + Priority: 5, Repositories: []TaskRepositoryInput{ { RepositoryID: "repo-123", @@ -460,8 +460,6 @@ func TestService_ListWorkflows(t *testing.T) { } } - - // Message tests func setupTestTask(t *testing.T, repo repository.Repository) { diff --git a/apps/backend/internal/user/controller/controller.go b/apps/backend/internal/user/controller/controller.go index d9c2db5b4c..5dbe87608f 100644 --- a/apps/backend/internal/user/controller/controller.go +++ b/apps/backend/internal/user/controller/controller.go @@ -44,15 +44,15 @@ func (c *Controller) GetUserSettings(ctx context.Context) (dto.UserSettingsRespo func (c *Controller) UpdateUserSettings(ctx context.Context, req dto.UpdateUserSettingsRequest) (dto.UserSettingsResponse, error) { settings, err := c.svc.UpdateUserSettings(ctx, &service.UpdateUserSettingsRequest{ - WorkspaceID: req.WorkspaceID, - KanbanViewMode: req.KanbanViewMode, - WorkflowFilterID: req.WorkflowFilterID, - RepositoryIDs: req.RepositoryIDs, - InitialSetupComplete: req.InitialSetupComplete, - PreferredShell: req.PreferredShell, - DefaultEditorID: req.DefaultEditorID, - EnablePreviewOnClick: req.EnablePreviewOnClick, - ChatSubmitKey: req.ChatSubmitKey, + WorkspaceID: req.WorkspaceID, + KanbanViewMode: req.KanbanViewMode, + WorkflowFilterID: req.WorkflowFilterID, + RepositoryIDs: req.RepositoryIDs, + InitialSetupComplete: req.InitialSetupComplete, + PreferredShell: req.PreferredShell, + DefaultEditorID: req.DefaultEditorID, + EnablePreviewOnClick: req.EnablePreviewOnClick, + ChatSubmitKey: req.ChatSubmitKey, ReviewAutoMarkOnScroll: req.ReviewAutoMarkOnScroll, LspAutoStartLanguages: req.LspAutoStartLanguages, LspAutoInstallLanguages: req.LspAutoInstallLanguages, diff --git a/apps/backend/internal/user/dto/dto.go b/apps/backend/internal/user/dto/dto.go index d7f07b03fd..2bd9fa5c82 100644 --- a/apps/backend/internal/user/dto/dto.go +++ b/apps/backend/internal/user/dto/dto.go @@ -14,17 +14,17 @@ type UserDTO struct { } type UserSettingsDTO struct { - UserID string `json:"user_id"` - WorkspaceID string `json:"workspace_id"` - KanbanViewMode string `json:"kanban_view_mode"` - WorkflowFilterID string `json:"workflow_filter_id"` - RepositoryIDs []string `json:"repository_ids"` - InitialSetupComplete bool `json:"initial_setup_complete"` - PreferredShell string `json:"preferred_shell"` - DefaultEditorID string `json:"default_editor_id"` - EnablePreviewOnClick bool `json:"enable_preview_on_click"` - ChatSubmitKey string `json:"chat_submit_key"` - ReviewAutoMarkOnScroll bool `json:"review_auto_mark_on_scroll"` + UserID string `json:"user_id"` + WorkspaceID string `json:"workspace_id"` + KanbanViewMode string `json:"kanban_view_mode"` + WorkflowFilterID string `json:"workflow_filter_id"` + RepositoryIDs []string `json:"repository_ids"` + InitialSetupComplete bool `json:"initial_setup_complete"` + PreferredShell string `json:"preferred_shell"` + DefaultEditorID string `json:"default_editor_id"` + EnablePreviewOnClick bool `json:"enable_preview_on_click"` + ChatSubmitKey string `json:"chat_submit_key"` + ReviewAutoMarkOnScroll bool `json:"review_auto_mark_on_scroll"` LspAutoStartLanguages []string `json:"lsp_auto_start_languages"` LspAutoInstallLanguages []string `json:"lsp_auto_install_languages"` LspServerConfigs map[string]map[string]interface{} `json:"lsp_server_configs,omitempty"` @@ -48,16 +48,16 @@ type ShellOption struct { } type UpdateUserSettingsRequest struct { - WorkspaceID *string `json:"workspace_id,omitempty"` - KanbanViewMode *string `json:"kanban_view_mode,omitempty"` - WorkflowFilterID *string `json:"workflow_filter_id,omitempty"` - RepositoryIDs *[]string `json:"repository_ids,omitempty"` - InitialSetupComplete *bool `json:"initial_setup_complete,omitempty"` - PreferredShell *string `json:"preferred_shell,omitempty"` - DefaultEditorID *string `json:"default_editor_id,omitempty"` - EnablePreviewOnClick *bool `json:"enable_preview_on_click,omitempty"` - ChatSubmitKey *string `json:"chat_submit_key,omitempty"` - ReviewAutoMarkOnScroll *bool `json:"review_auto_mark_on_scroll,omitempty"` + WorkspaceID *string `json:"workspace_id,omitempty"` + KanbanViewMode *string `json:"kanban_view_mode,omitempty"` + WorkflowFilterID *string `json:"workflow_filter_id,omitempty"` + RepositoryIDs *[]string `json:"repository_ids,omitempty"` + InitialSetupComplete *bool `json:"initial_setup_complete,omitempty"` + PreferredShell *string `json:"preferred_shell,omitempty"` + DefaultEditorID *string `json:"default_editor_id,omitempty"` + EnablePreviewOnClick *bool `json:"enable_preview_on_click,omitempty"` + ChatSubmitKey *string `json:"chat_submit_key,omitempty"` + ReviewAutoMarkOnScroll *bool `json:"review_auto_mark_on_scroll,omitempty"` LspAutoStartLanguages *[]string `json:"lsp_auto_start_languages,omitempty"` LspAutoInstallLanguages *[]string `json:"lsp_auto_install_languages,omitempty"` LspServerConfigs *map[string]map[string]interface{} `json:"lsp_server_configs,omitempty"` @@ -75,16 +75,16 @@ func FromUser(user *models.User) UserDTO { func FromUserSettings(settings *models.UserSettings) UserSettingsDTO { return UserSettingsDTO{ - UserID: settings.UserID, - WorkspaceID: settings.WorkspaceID, - KanbanViewMode: settings.KanbanViewMode, - WorkflowFilterID: settings.WorkflowFilterID, - RepositoryIDs: settings.RepositoryIDs, - InitialSetupComplete: settings.InitialSetupComplete, - PreferredShell: settings.PreferredShell, - DefaultEditorID: settings.DefaultEditorID, - EnablePreviewOnClick: settings.EnablePreviewOnClick, - ChatSubmitKey: settings.ChatSubmitKey, + UserID: settings.UserID, + WorkspaceID: settings.WorkspaceID, + KanbanViewMode: settings.KanbanViewMode, + WorkflowFilterID: settings.WorkflowFilterID, + RepositoryIDs: settings.RepositoryIDs, + InitialSetupComplete: settings.InitialSetupComplete, + PreferredShell: settings.PreferredShell, + DefaultEditorID: settings.DefaultEditorID, + EnablePreviewOnClick: settings.EnablePreviewOnClick, + ChatSubmitKey: settings.ChatSubmitKey, ReviewAutoMarkOnScroll: settings.ReviewAutoMarkOnScroll, LspAutoStartLanguages: settings.LspAutoStartLanguages, LspAutoInstallLanguages: settings.LspAutoInstallLanguages, diff --git a/apps/backend/internal/user/models/models.go b/apps/backend/internal/user/models/models.go index 7a47331144..03fa8ca2bd 100644 --- a/apps/backend/internal/user/models/models.go +++ b/apps/backend/internal/user/models/models.go @@ -13,23 +13,23 @@ type User struct { } type UserSettings struct { - UserID string `json:"user_id"` - WorkspaceID string `json:"workspace_id"` - KanbanViewMode string `json:"kanban_view_mode"` - WorkflowFilterID string `json:"workflow_filter_id"` - RepositoryIDs []string `json:"repository_ids"` - InitialSetupComplete bool `json:"initial_setup_complete"` - PreferredShell string `json:"preferred_shell"` - DefaultEditorID string `json:"default_editor_id"` - EnablePreviewOnClick bool `json:"enable_preview_on_click"` - ChatSubmitKey string `json:"chat_submit_key"` // "enter" | "cmd_enter" - ReviewAutoMarkOnScroll bool `json:"review_auto_mark_on_scroll"` + UserID string `json:"user_id"` + WorkspaceID string `json:"workspace_id"` + KanbanViewMode string `json:"kanban_view_mode"` + WorkflowFilterID string `json:"workflow_filter_id"` + RepositoryIDs []string `json:"repository_ids"` + InitialSetupComplete bool `json:"initial_setup_complete"` + PreferredShell string `json:"preferred_shell"` + DefaultEditorID string `json:"default_editor_id"` + EnablePreviewOnClick bool `json:"enable_preview_on_click"` + ChatSubmitKey string `json:"chat_submit_key"` // "enter" | "cmd_enter" + ReviewAutoMarkOnScroll bool `json:"review_auto_mark_on_scroll"` LspAutoStartLanguages []string `json:"lsp_auto_start_languages"` LspAutoInstallLanguages []string `json:"lsp_auto_install_languages"` LspServerConfigs map[string]map[string]interface{} `json:"lsp_server_configs"` SavedLayouts []SavedLayout `json:"saved_layouts"` CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + UpdatedAt time.Time `json:"updated_at"` } // SavedLayout represents a user-saved dockview layout configuration. diff --git a/apps/backend/internal/user/service/service.go b/apps/backend/internal/user/service/service.go index 77a0a8cf11..20c785d955 100644 --- a/apps/backend/internal/user/service/service.go +++ b/apps/backend/internal/user/service/service.go @@ -26,15 +26,15 @@ type Service struct { } type UpdateUserSettingsRequest struct { - WorkspaceID *string - KanbanViewMode *string - WorkflowFilterID *string - RepositoryIDs *[]string - InitialSetupComplete *bool - PreferredShell *string - DefaultEditorID *string - EnablePreviewOnClick *bool - ChatSubmitKey *string + WorkspaceID *string + KanbanViewMode *string + WorkflowFilterID *string + RepositoryIDs *[]string + InitialSetupComplete *bool + PreferredShell *string + DefaultEditorID *string + EnablePreviewOnClick *bool + ChatSubmitKey *string ReviewAutoMarkOnScroll *bool LspAutoStartLanguages *[]string LspAutoInstallLanguages *[]string @@ -191,17 +191,17 @@ func (s *Service) publishUserSettingsEvent(ctx context.Context, settings *models return } data := map[string]interface{}{ - "user_id": settings.UserID, - "workspace_id": settings.WorkspaceID, - "kanban_view_mode": settings.KanbanViewMode, - "workflow_filter_id": settings.WorkflowFilterID, - "repository_ids": settings.RepositoryIDs, - "initial_setup_complete": settings.InitialSetupComplete, - "preferred_shell": settings.PreferredShell, - "default_editor_id": settings.DefaultEditorID, + "user_id": settings.UserID, + "workspace_id": settings.WorkspaceID, + "kanban_view_mode": settings.KanbanViewMode, + "workflow_filter_id": settings.WorkflowFilterID, + "repository_ids": settings.RepositoryIDs, + "initial_setup_complete": settings.InitialSetupComplete, + "preferred_shell": settings.PreferredShell, + "default_editor_id": settings.DefaultEditorID, "enable_preview_on_click": settings.EnablePreviewOnClick, "chat_submit_key": settings.ChatSubmitKey, - "review_auto_mark_on_scroll": settings.ReviewAutoMarkOnScroll, + "review_auto_mark_on_scroll": settings.ReviewAutoMarkOnScroll, "lsp_auto_start_languages": settings.LspAutoStartLanguages, "lsp_auto_install_languages": settings.LspAutoInstallLanguages, "lsp_server_configs": settings.LspServerConfigs, diff --git a/apps/backend/internal/user/store/sqlite.go b/apps/backend/internal/user/store/sqlite.go index 6be08e8625..b22eac02da 100644 --- a/apps/backend/internal/user/store/sqlite.go +++ b/apps/backend/internal/user/store/sqlite.go @@ -186,16 +186,16 @@ func scanUserSettings(scanner interface{ Scan(dest ...any) error }, userID strin return settings, nil } var payload struct { - WorkspaceID string `json:"workspace_id"` - KanbanViewMode string `json:"kanban_view_mode"` - WorkflowFilterID string `json:"workflow_filter_id"` - RepositoryIDs []string `json:"repository_ids"` - InitialSetupComplete bool `json:"initial_setup_complete"` - PreferredShell string `json:"preferred_shell"` - DefaultEditorID string `json:"default_editor_id"` - EnablePreviewOnClick bool `json:"enable_preview_on_click"` - ChatSubmitKey string `json:"chat_submit_key"` - ReviewAutoMarkOnScroll *bool `json:"review_auto_mark_on_scroll"` + WorkspaceID string `json:"workspace_id"` + KanbanViewMode string `json:"kanban_view_mode"` + WorkflowFilterID string `json:"workflow_filter_id"` + RepositoryIDs []string `json:"repository_ids"` + InitialSetupComplete bool `json:"initial_setup_complete"` + PreferredShell string `json:"preferred_shell"` + DefaultEditorID string `json:"default_editor_id"` + EnablePreviewOnClick bool `json:"enable_preview_on_click"` + ChatSubmitKey string `json:"chat_submit_key"` + ReviewAutoMarkOnScroll *bool `json:"review_auto_mark_on_scroll"` LspAutoStartLanguages []string `json:"lsp_auto_start_languages"` LspAutoInstallLanguages []string `json:"lsp_auto_install_languages"` LspServerConfigs map[string]map[string]interface{} `json:"lsp_server_configs"` diff --git a/apps/backend/internal/workflow/controller/controller.go b/apps/backend/internal/workflow/controller/controller.go index 0c1c4741c1..b11aff00c4 100644 --- a/apps/backend/internal/workflow/controller/controller.go +++ b/apps/backend/internal/workflow/controller/controller.go @@ -84,14 +84,14 @@ func (c *Controller) CreateStepsFromTemplate(ctx context.Context, req CreateStep // CreateStepRequest is the request for creating a single workflow step. type CreateStepRequest struct { - WorkflowID string `json:"workflow_id"` - Name string `json:"name"` - Position int `json:"position"` - Color string `json:"color"` - Prompt string `json:"prompt,omitempty"` + WorkflowID string `json:"workflow_id"` + Name string `json:"name"` + Position int `json:"position"` + Color string `json:"color"` + Prompt string `json:"prompt,omitempty"` Events *models.StepEvents `json:"events,omitempty"` - AllowManualMove bool `json:"allow_manual_move"` - IsStartStep *bool `json:"is_start_step,omitempty"` + AllowManualMove bool `json:"allow_manual_move"` + IsStartStep *bool `json:"is_start_step,omitempty"` } // CreateStep creates a new workflow step. @@ -203,7 +203,7 @@ func (c *Controller) ListHistoryBySession(ctx context.Context, req ListHistoryRe // ImportWorkflowsRequest carries import data. type ImportWorkflowsRequest struct { - WorkspaceID string `json:"workspace_id"` + WorkspaceID string `json:"workspace_id"` Data *models.WorkflowExport `json:"data"` } diff --git a/apps/backend/internal/workflow/handlers/handlers.go b/apps/backend/internal/workflow/handlers/handlers.go index 3a5d1e48b4..3b0b6b82a4 100644 --- a/apps/backend/internal/workflow/handlers/handlers.go +++ b/apps/backend/internal/workflow/handlers/handlers.go @@ -190,7 +190,7 @@ func (h *Handlers) httpReorderSteps(c *gin.Context) { } if err := h.controller.ReorderSteps(c.Request.Context(), controller.ReorderStepsRequest{ WorkflowID: c.Param("id"), - StepIDs: req.StepIDs, + StepIDs: req.StepIDs, }); err != nil { h.logger.Error("failed to reorder steps", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to reorder steps"}) @@ -334,4 +334,3 @@ func (h *Handlers) wsListHistory(ctx context.Context, msg *ws.Message) (*ws.Mess return h.controller.ListHistoryBySession(ctx, controller.ListHistoryRequest{SessionID: sessionID}) }) } - diff --git a/apps/backend/internal/workflow/models/models.go b/apps/backend/internal/workflow/models/models.go index 695c770023..cbe8b990d1 100644 --- a/apps/backend/internal/workflow/models/models.go +++ b/apps/backend/internal/workflow/models/models.go @@ -67,7 +67,7 @@ type OnExitAction struct { type StepEvents struct { OnEnter []OnEnterAction `json:"on_enter,omitempty"` OnTurnStart []OnTurnStartAction `json:"on_turn_start,omitempty"` - OnTurnComplete []OnTurnCompleteAction `json:"on_turn_complete,omitempty"` + OnTurnComplete []OnTurnCompleteAction `json:"on_turn_complete,omitempty"` OnExit []OnExitAction `json:"on_exit,omitempty"` } diff --git a/apps/backend/internal/workflow/repository/sqlite.go b/apps/backend/internal/workflow/repository/sqlite.go index d02a16e67d..f3715533f5 100644 --- a/apps/backend/internal/workflow/repository/sqlite.go +++ b/apps/backend/internal/workflow/repository/sqlite.go @@ -109,7 +109,6 @@ func (r *Repository) initSchema() error { return nil } - // seedDefaultWorkflowSteps creates default workflow steps for workflows that don't have any. // Uses the simple template as the default workflow. func (r *Repository) seedDefaultWorkflowSteps() error { @@ -406,7 +405,6 @@ func (r *Repository) getKanbanTemplate(now time.Time) *models.WorkflowTemplate { } } - // getPRReviewTemplate returns the PR review workflow template. func (r *Repository) getPRReviewTemplate(now time.Time) *models.WorkflowTemplate { return &models.WorkflowTemplate{ diff --git a/apps/backend/internal/workflow/service/service.go b/apps/backend/internal/workflow/service/service.go index eaa502da6f..bfd3014cb8 100644 --- a/apps/backend/internal/workflow/service/service.go +++ b/apps/backend/internal/workflow/service/service.go @@ -452,4 +452,3 @@ func (s *Service) importSingleWorkflow(ctx context.Context, workspaceID string, } return nil } - diff --git a/apps/backend/internal/worktree/errors.go b/apps/backend/internal/worktree/errors.go index 64c0d9e378..cbb05eb977 100644 --- a/apps/backend/internal/worktree/errors.go +++ b/apps/backend/internal/worktree/errors.go @@ -31,4 +31,3 @@ var ( // ErrInvalidSession is returned when the session ID is invalid or empty. ErrInvalidSession = errors.New("invalid or empty session ID") ) - diff --git a/apps/backend/pkg/acp/jsonrpc/types.go b/apps/backend/pkg/acp/jsonrpc/types.go index 6c429e2c6a..6c7a02c393 100644 --- a/apps/backend/pkg/acp/jsonrpc/types.go +++ b/apps/backend/pkg/acp/jsonrpc/types.go @@ -5,7 +5,7 @@ import "encoding/json" // Request represents a JSON-RPC 2.0 request type Request struct { - JSONRPC string `json:"jsonrpc"` // Always "2.0" + JSONRPC string `json:"jsonrpc"` // Always "2.0" ID interface{} `json:"id,omitempty"` // Request ID (int or string), omit for notifications Method string `json:"method"` Params json.RawMessage `json:"params,omitempty"` @@ -45,12 +45,12 @@ const ( // ACP Methods const ( // Client -> Agent methods - MethodInitialize = "initialize" - MethodSessionNew = "session/new" - MethodSessionPrompt = "session/prompt" - MethodSessionLoad = "session/load" - MethodSessionCancel = "session/cancel" - MethodAuthenticate = "authenticate" + MethodInitialize = "initialize" + MethodSessionNew = "session/new" + MethodSessionPrompt = "session/prompt" + MethodSessionLoad = "session/load" + MethodSessionCancel = "session/cancel" + MethodAuthenticate = "authenticate" // Agent -> Client notifications NotificationSessionUpdate = "session/update" @@ -61,9 +61,9 @@ const ( // InitializeParams for initialize method type InitializeParams struct { - ProtocolVersion int `json:"protocolVersion"` - ClientInfo ClientInfo `json:"clientInfo"` - Capabilities ClientCapabilities `json:"capabilities,omitempty"` + ProtocolVersion int `json:"protocolVersion"` + ClientInfo ClientInfo `json:"clientInfo"` + Capabilities ClientCapabilities `json:"capabilities,omitempty"` } // ClientInfo identifies the client @@ -119,7 +119,7 @@ type SessionNewResult struct { // ContentBlock represents a content block in ACP protocol // The prompt field in session/prompt is an array of ContentBlock type ContentBlock struct { - Type string `json:"type"` // "text", "resource", "image", etc. + Type string `json:"type"` // "text", "resource", "image", etc. Text string `json:"text,omitempty"` // For type="text" // Resource *ResourceContent `json:"resource,omitempty"` // For type="resource" (not implemented yet) } @@ -186,9 +186,9 @@ type SessionUpdateInputRequested struct { // RequestPermissionParams for session/request_permission request from agent type RequestPermissionParams struct { - SessionID string `json:"sessionId"` - ToolCall ToolCallUpdate `json:"toolCall"` - Options []PermissionOption `json:"options"` + SessionID string `json:"sessionId"` + ToolCall ToolCallUpdate `json:"toolCall"` + Options []PermissionOption `json:"options"` } // ToolCallUpdate contains tool call information in permission requests @@ -211,6 +211,6 @@ type RequestPermissionResult struct { // PermissionOutcome represents the user's decision type PermissionOutcome struct { - Outcome string `json:"outcome"` // "selected" or "cancelled" + Outcome string `json:"outcome"` // "selected" or "cancelled" OptionID string `json:"optionId,omitempty"` // Only present when outcome="selected" } diff --git a/apps/backend/pkg/acp/protocol/types.go b/apps/backend/pkg/acp/protocol/types.go index 22acf2e3c8..07f5cad1ef 100644 --- a/apps/backend/pkg/acp/protocol/types.go +++ b/apps/backend/pkg/acp/protocol/types.go @@ -2,7 +2,7 @@ package protocol // ProgressData represents progress update data type ProgressData struct { - Progress int `json:"progress"` // 0-100 + Progress int `json:"progress"` // 0-100 Message string `json:"message"` CurrentFile string `json:"current_file,omitempty"` FilesProcessed int `json:"files_processed,omitempty"` @@ -51,15 +51,15 @@ type ControlData struct { // InputRequiredData represents a request for user input (Agent → Backend) type InputRequiredData struct { - PromptID string `json:"prompt_id"` // Unique ID for this prompt - Prompt string `json:"prompt"` // Question/prompt for the user - InputType string `json:"input_type"` // text, choice, confirm, file - Options []string `json:"options,omitempty"` // For choice type - Default string `json:"default,omitempty"` // Default value - Required bool `json:"required"` // Whether input is required - Timeout int `json:"timeout,omitempty"` // Timeout in seconds (0 = no timeout) - Context string `json:"context,omitempty"` // Additional context for the prompt - Validation string `json:"validation,omitempty"` // Validation pattern (regex) + PromptID string `json:"prompt_id"` // Unique ID for this prompt + Prompt string `json:"prompt"` // Question/prompt for the user + InputType string `json:"input_type"` // text, choice, confirm, file + Options []string `json:"options,omitempty"` // For choice type + Default string `json:"default,omitempty"` // Default value + Required bool `json:"required"` // Whether input is required + Timeout int `json:"timeout,omitempty"` // Timeout in seconds (0 = no timeout) + Context string `json:"context,omitempty"` // Additional context for the prompt + Validation string `json:"validation,omitempty"` // Validation pattern (regex) } // InputResponseData represents user's response to input request (Backend → Agent) @@ -71,10 +71,10 @@ type InputResponseData struct { // SessionInfoData represents session information from the agent type SessionInfoData struct { - SessionID string `json:"session_id"` - Resumable bool `json:"resumable"` - StartedAt string `json:"started_at,omitempty"` - Metadata map[string]interface{} `json:"metadata,omitempty"` + SessionID string `json:"session_id"` + Resumable bool `json:"resumable"` + StartedAt string `json:"started_at,omitempty"` + Metadata map[string]interface{} `json:"metadata,omitempty"` } // AgentCapabilities represents what the agent can do diff --git a/apps/backend/pkg/agent/protocol.go b/apps/backend/pkg/agent/protocol.go index 00256e176d..3de9d4505d 100644 --- a/apps/backend/pkg/agent/protocol.go +++ b/apps/backend/pkg/agent/protocol.go @@ -46,4 +46,3 @@ func (p Protocol) IsValid() bool { return false } } - diff --git a/apps/backend/pkg/amp/client.go b/apps/backend/pkg/amp/client.go index 43930a8eea..eec20dfe61 100644 --- a/apps/backend/pkg/amp/client.go +++ b/apps/backend/pkg/amp/client.go @@ -60,7 +60,7 @@ type Message struct { // Result fields (when Type == "result") IsError bool `json:"is_error,omitempty"` - Error string `json:"error,omitempty"` // Error message when is_error is true + Error string `json:"error,omitempty"` // Error message when is_error is true Subtype string `json:"subtype,omitempty"` // e.g., "error_during_execution" CostUSD float64 `json:"cost_usd,omitempty"` DurationMS int64 `json:"duration_ms,omitempty"` @@ -73,11 +73,11 @@ type Message struct { // Content represents the message content. type Content struct { - Model string `json:"model,omitempty"` - Content []ContentBlock `json:"content,omitempty"` - Usage *TokenUsage `json:"usage,omitempty"` - StopReason string `json:"stop_reason,omitempty"` - StopSequence string `json:"stop_sequence,omitempty"` + Model string `json:"model,omitempty"` + Content []ContentBlock `json:"content,omitempty"` + Usage *TokenUsage `json:"usage,omitempty"` + StopReason string `json:"stop_reason,omitempty"` + StopSequence string `json:"stop_sequence,omitempty"` } // ContentBlock represents a content block (text, tool_use, etc.). @@ -117,14 +117,14 @@ type ResultData struct { // UserMessage represents a user message to send (Claude Code-compatible format). type UserMessage struct { - Type string `json:"type"` // "user" + Type string `json:"type"` // "user" Message UserMessageBody `json:"message"` } // UserMessageBody is the nested message body for user messages. type UserMessageBody struct { - Role string `json:"role"` // "user" - Content []UserContentBlock `json:"content"` + Role string `json:"role"` // "user" + Content []UserContentBlock `json:"content"` } // UserContentBlock represents a content block in user messages. diff --git a/apps/backend/pkg/api/v1/agent.go b/apps/backend/pkg/api/v1/agent.go index 498bab2f24..24a8da76ca 100644 --- a/apps/backend/pkg/api/v1/agent.go +++ b/apps/backend/pkg/api/v1/agent.go @@ -58,8 +58,8 @@ type AgentType struct { type AgentLog struct { ID int64 `json:"id"` AgentExecutionID string `json:"agent_execution_id"` - LogLevel string `json:"log_level"` - Message string `json:"message"` - Metadata map[string]interface{} `json:"metadata,omitempty"` - CreatedAt time.Time `json:"created_at"` + LogLevel string `json:"log_level"` + Message string `json:"message"` + Metadata map[string]interface{} `json:"metadata,omitempty"` + CreatedAt time.Time `json:"created_at"` } diff --git a/apps/backend/pkg/api/v1/user.go b/apps/backend/pkg/api/v1/user.go index ba09740e81..9fd42cfb4d 100644 --- a/apps/backend/pkg/api/v1/user.go +++ b/apps/backend/pkg/api/v1/user.go @@ -16,7 +16,7 @@ type UserSettings struct { KanbanViewMode string `json:"kanban_view_mode"` WorkflowFilterID string `json:"workflow_filter_id"` RepositoryIDs []string `json:"repository_ids"` - PreferredShell string `json:"preferred_shell"` - DefaultEditorID string `json:"default_editor_id"` - UpdatedAt time.Time `json:"updated_at"` + PreferredShell string `json:"preferred_shell"` + DefaultEditorID string `json:"default_editor_id"` + UpdatedAt time.Time `json:"updated_at"` } diff --git a/apps/backend/pkg/claudecode/types.go b/apps/backend/pkg/claudecode/types.go index 1c1341b35b..9405687b7b 100644 --- a/apps/backend/pkg/claudecode/types.go +++ b/apps/backend/pkg/claudecode/types.go @@ -144,8 +144,8 @@ type ContentBlock struct { // Usage contains token usage information. type Usage struct { - InputTokens int64 `json:"input_tokens"` - OutputTokens int64 `json:"output_tokens"` + InputTokens int64 `json:"input_tokens"` + OutputTokens int64 `json:"output_tokens"` CacheCreationInputTokens int64 `json:"cache_creation_input_tokens,omitempty"` CacheReadInputTokens int64 `json:"cache_read_input_tokens,omitempty"` } diff --git a/apps/backend/pkg/codex/types.go b/apps/backend/pkg/codex/types.go index fe465a22cf..b065132cd6 100644 --- a/apps/backend/pkg/codex/types.go +++ b/apps/backend/pkg/codex/types.go @@ -196,11 +196,11 @@ type Item struct { Content FlexibleContent `json:"content,omitempty"` // For mcpToolCall type - Server string `json:"server,omitempty"` - Tool string `json:"tool,omitempty"` - Arguments json.RawMessage `json:"arguments,omitempty"` - Result json.RawMessage `json:"result,omitempty"` - ToolError string `json:"error,omitempty"` // Named ToolError to avoid conflict with Error type + Server string `json:"server,omitempty"` + Tool string `json:"tool,omitempty"` + Arguments json.RawMessage `json:"arguments,omitempty"` + Result json.RawMessage `json:"result,omitempty"` + ToolError string `json:"error,omitempty"` // Named ToolError to avoid conflict with Error type } // ContentPart represents a content part in a Codex item. @@ -358,7 +358,7 @@ type ErrorParams struct { // TokenCountParams for token_count notification // This is emitted by Codex after each turn to report token usage. type TokenCountParams struct { - Info *TokenUsageInfo `json:"info,omitempty"` + Info *TokenUsageInfo `json:"info,omitempty"` RateLimits *RateLimitSnapshot `json:"rateLimits,omitempty"` } @@ -381,9 +381,9 @@ type TokenUsage struct { // ThreadTokenUsageUpdatedParams for thread/tokenUsage/updated notification. // This is emitted by Codex after each turn completes with token usage info. type ThreadTokenUsageUpdatedParams struct { - ThreadID string `json:"threadId"` - TurnID string `json:"turnId"` - TokenUsage *ThreadTokenUsage `json:"tokenUsage"` + ThreadID string `json:"threadId"` + TurnID string `json:"turnId"` + TokenUsage *ThreadTokenUsage `json:"tokenUsage"` } // ThreadTokenUsage contains the token usage summary for a thread. @@ -403,9 +403,9 @@ type RateLimitSnapshot struct { // RateLimitWindow contains rate limit window information. type RateLimitWindow struct { - UsedPercent int32 `json:"usedPercent"` + UsedPercent int32 `json:"usedPercent"` WindowDurationMins *int64 `json:"windowDurationMins,omitempty"` - ResetsAt *int64 `json:"resetsAt,omitempty"` + ResetsAt *int64 `json:"resetsAt,omitempty"` } // CreditsSnapshot contains credits information (placeholder for future use). diff --git a/apps/backend/pkg/copilot/client.go b/apps/backend/pkg/copilot/client.go index e9d24c5811..5a4bc1c51f 100644 --- a/apps/backend/pkg/copilot/client.go +++ b/apps/backend/pkg/copilot/client.go @@ -26,32 +26,32 @@ type ( MessageOptions = copilot.MessageOptions Data = copilot.Data // Permission types - PermissionHandler = copilot.PermissionHandler - PermissionRequest = copilot.PermissionRequest - PermissionInvocation = copilot.PermissionInvocation - PermissionRequestResult = copilot.PermissionRequestResult + PermissionHandler = copilot.PermissionHandler + PermissionRequest = copilot.PermissionRequest + PermissionInvocation = copilot.PermissionInvocation + PermissionRequestResult = copilot.PermissionRequestResult // MCP types MCPServerConfig = copilot.MCPServerConfig ) // Re-export event type constants const ( - EventTypeSessionStart = copilot.SessionStart - EventTypeSessionResume = copilot.SessionResume - EventTypeSessionIdle = copilot.SessionIdle - EventTypeSessionError = copilot.SessionError - EventTypeSessionUsageInfo = copilot.SessionUsageInfo - EventTypeAssistantMessage = copilot.AssistantMessage - EventTypeAssistantMessageDelta = copilot.AssistantMessageDelta - EventTypeAssistantReasoning = copilot.AssistantReasoning + EventTypeSessionStart = copilot.SessionStart + EventTypeSessionResume = copilot.SessionResume + EventTypeSessionIdle = copilot.SessionIdle + EventTypeSessionError = copilot.SessionError + EventTypeSessionUsageInfo = copilot.SessionUsageInfo + EventTypeAssistantMessage = copilot.AssistantMessage + EventTypeAssistantMessageDelta = copilot.AssistantMessageDelta + EventTypeAssistantReasoning = copilot.AssistantReasoning EventTypeAssistantReasoningDelta = copilot.AssistantReasoningDelta - EventTypeAssistantTurnStart = copilot.AssistantTurnStart - EventTypeAssistantTurnEnd = copilot.AssistantTurnEnd - EventTypeAssistantUsage = copilot.AssistantUsage - EventTypeToolStart = copilot.ToolExecutionStart - EventTypeToolComplete = copilot.ToolExecutionComplete - EventTypeToolProgress = copilot.ToolExecutionProgress - EventTypeAbort = copilot.Abort + EventTypeAssistantTurnStart = copilot.AssistantTurnStart + EventTypeAssistantTurnEnd = copilot.AssistantTurnEnd + EventTypeAssistantUsage = copilot.AssistantUsage + EventTypeToolStart = copilot.ToolExecutionStart + EventTypeToolComplete = copilot.ToolExecutionComplete + EventTypeToolProgress = copilot.ToolExecutionProgress + EventTypeAbort = copilot.Abort ) // Client wraps the Copilot SDK client with additional functionality. @@ -65,9 +65,9 @@ type Client struct { model string // Event handler - eventHandler func(SessionEvent) - unsubscribe func() - handlerMu sync.RWMutex + eventHandler func(SessionEvent) + unsubscribe func() + handlerMu sync.RWMutex // Permission handler permissionHandler PermissionHandler diff --git a/apps/backend/pkg/opencode/types.go b/apps/backend/pkg/opencode/types.go index 7d6a8bb9b5..ade4736777 100644 --- a/apps/backend/pkg/opencode/types.go +++ b/apps/backend/pkg/opencode/types.go @@ -117,13 +117,13 @@ type MessageUpdatedProperties struct { // MessageInfo contains message metadata type MessageInfo struct { - ID string `json:"id"` - SessionID string `json:"sessionID"` - Role string `json:"role"` // "user", "assistant" - Model *MessageModelInfo `json:"model,omitempty"` - ProviderID string `json:"providerID,omitempty"` - ModelID string `json:"modelID,omitempty"` - Tokens *MessageTokensInfo `json:"tokens,omitempty"` + ID string `json:"id"` + SessionID string `json:"sessionID"` + Role string `json:"role"` // "user", "assistant" + Model *MessageModelInfo `json:"model,omitempty"` + ProviderID string `json:"providerID,omitempty"` + ModelID string `json:"modelID,omitempty"` + Tokens *MessageTokensInfo `json:"tokens,omitempty"` } // MessageModelInfo contains model information @@ -134,8 +134,8 @@ type MessageModelInfo struct { // MessageTokensInfo contains token usage information type MessageTokensInfo struct { - Input int `json:"input"` - Output int `json:"output"` + Input int `json:"input"` + Output int `json:"output"` Cache *MessageTokensCacheInfo `json:"cache,omitempty"` } @@ -156,10 +156,10 @@ type Part struct { Type string `json:"type"` // "text", "reasoning", "tool" MessageID string `json:"messageID"` SessionID string `json:"sessionID"` - Text string `json:"text,omitempty"` // For text/reasoning - CallID string `json:"callID,omitempty"` // For tool - Tool string `json:"tool,omitempty"` // For tool - State *ToolStateUpdate `json:"state,omitempty"` // For tool + Text string `json:"text,omitempty"` // For text/reasoning + CallID string `json:"callID,omitempty"` // For tool + Tool string `json:"tool,omitempty"` // For tool + State *ToolStateUpdate `json:"state,omitempty"` // For tool } // ToolStateUpdate represents tool execution state @@ -174,12 +174,12 @@ type ToolStateUpdate struct { // PermissionAskedProperties for permission.asked events type PermissionAskedProperties struct { - ID string `json:"id"` - SessionID string `json:"sessionID"` - Permission string `json:"permission"` - Patterns []string `json:"patterns,omitempty"` - Metadata map[string]any `json:"metadata,omitempty"` - Tool *PermissionToolInfo `json:"tool,omitempty"` + ID string `json:"id"` + SessionID string `json:"sessionID"` + Permission string `json:"permission"` + Patterns []string `json:"patterns,omitempty"` + Metadata map[string]any `json:"metadata,omitempty"` + Tool *PermissionToolInfo `json:"tool,omitempty"` } // PermissionToolInfo contains tool information for permission requests @@ -194,8 +194,8 @@ type SessionIdleProperties struct { // SessionErrorProperties for session.error events type SessionErrorProperties struct { - SessionID string `json:"sessionID"` - Error *SDKError `json:"error,omitempty"` + SessionID string `json:"sessionID"` + Error *SDKError `json:"error,omitempty"` } // SDKError represents an error from the SDK @@ -260,7 +260,7 @@ type ProviderListResponse struct { // ProviderInfo contains provider information type ProviderInfo struct { - ID string `json:"id"` + ID string `json:"id"` Models map[string]ProviderModelInfo `json:"models,omitempty"` } diff --git a/apps/backend/pkg/opencode/types_test.go b/apps/backend/pkg/opencode/types_test.go index c6c6125455..7caec3b89e 100644 --- a/apps/backend/pkg/opencode/types_test.go +++ b/apps/backend/pkg/opencode/types_test.go @@ -294,7 +294,9 @@ func TestSDKError_GetMessage(t *testing.T) { name: "data.message takes precedence", err: SDKError{ Message: "outer message", - Data: &struct{ Message string `json:"message,omitempty"` }{Message: "inner message"}, + Data: &struct { + Message string `json:"message,omitempty"` + }{Message: "inner message"}, }, wantMessage: "inner message", }, diff --git a/apps/backend/pkg/websocket/actions.go b/apps/backend/pkg/websocket/actions.go index b6924acbf0..3713edfb5e 100644 --- a/apps/backend/pkg/websocket/actions.go +++ b/apps/backend/pkg/websocket/actions.go @@ -48,18 +48,18 @@ const ( ActionEnvironmentDelete = "environment.delete" // Task actions - ActionTaskList = "task.list" - ActionTaskCreate = "task.create" - ActionTaskGet = "task.get" - ActionTaskUpdate = "task.update" - ActionTaskDelete = "task.delete" - ActionTaskMove = "task.move" - ActionTaskState = "task.state" - ActionTaskArchive = "task.archive" - ActionTaskPlanCreate = "task.plan.create" - ActionTaskPlanGet = "task.plan.get" - ActionTaskPlanUpdate = "task.plan.update" - ActionTaskPlanDelete = "task.plan.delete" + ActionTaskList = "task.list" + ActionTaskCreate = "task.create" + ActionTaskGet = "task.get" + ActionTaskUpdate = "task.update" + ActionTaskDelete = "task.delete" + ActionTaskMove = "task.move" + ActionTaskState = "task.state" + ActionTaskArchive = "task.archive" + ActionTaskPlanCreate = "task.plan.create" + ActionTaskPlanGet = "task.plan.get" + ActionTaskPlanUpdate = "task.plan.update" + ActionTaskPlanDelete = "task.plan.delete" ActionTaskSessionList = "task.session.list" ActionTaskSessionResume = "task.session.resume" @@ -93,19 +93,19 @@ const ( ActionOrchestratorComplete = "orchestrator.complete" // Message Queue actions - ActionMessageQueueAdd = "message.queue.add" - ActionMessageQueueCancel = "message.queue.cancel" - ActionMessageQueueGet = "message.queue.get" - ActionMessageQueueUpdate = "message.queue.update" - ActionMessageQueueStatusChanged = "message.queue.status_changed" // Notification: queue status changed + ActionMessageQueueAdd = "message.queue.add" + ActionMessageQueueCancel = "message.queue.cancel" + ActionMessageQueueGet = "message.queue.get" + ActionMessageQueueUpdate = "message.queue.update" + ActionMessageQueueStatusChanged = "message.queue.status_changed" // Notification: queue status changed // Workflow template/step actions - ActionWorkflowTemplateList = "workflow.template.list" - ActionWorkflowTemplateGet = "workflow.template.get" - ActionWorkflowStepList = "workflow.step.list" - ActionWorkflowStepGet = "workflow.step.get" - ActionWorkflowStepCreate = "workflow.step.create" - ActionWorkflowHistoryList = "workflow.history.list" + ActionWorkflowTemplateList = "workflow.template.list" + ActionWorkflowTemplateGet = "workflow.template.get" + ActionWorkflowStepList = "workflow.step.list" + ActionWorkflowStepGet = "workflow.step.get" + ActionWorkflowStepCreate = "workflow.step.create" + ActionWorkflowHistoryList = "workflow.history.list" // Subscription actions ActionTaskSubscribe = "task.subscribe" @@ -121,50 +121,50 @@ const ( ActionMessageList = "message.list" // Notification actions (server -> client) - ActionACPProgress = "acp.progress" - ActionACPLog = "acp.log" - ActionACPResult = "acp.result" - ActionACPError = "acp.error" - ActionACPStatus = "acp.status" - ActionACPHeartbeat = "acp.heartbeat" - ActionTaskCreated = "task.created" - ActionTaskUpdated = "task.updated" - ActionTaskDeleted = "task.deleted" - ActionTaskStateChanged = "task.state_changed" - ActionTaskPlanCreated = "task.plan.created" - ActionTaskPlanUpdated = "task.plan.updated" - ActionTaskPlanDeleted = "task.plan.deleted" - ActionAgentUpdated = "agent.updated" - ActionAgentAvailableUpdated = "agent.available.updated" - ActionWorkspaceCreated = "workspace.created" - ActionWorkspaceUpdated = "workspace.updated" - ActionWorkspaceDeleted = "workspace.deleted" - ActionWorkflowCreated = "workflow.created" - ActionWorkflowUpdated = "workflow.updated" - ActionWorkflowDeleted = "workflow.deleted" - ActionSessionMessageAdded = "session.message.added" - ActionSessionMessageUpdated = "session.message.updated" - ActionSessionStateChanged = "session.state_changed" - ActionSessionWaitingForInput = "session.waiting_for_input" - ActionSessionAgentctlStarting = "session.agentctl_starting" - ActionSessionAgentctlReady = "session.agentctl_ready" - ActionSessionAgentctlError = "session.agentctl_error" - ActionSessionTurnStarted = "session.turn.started" - ActionSessionTurnCompleted = "session.turn.completed" - ActionSessionAvailableCommands = "session.available_commands" - ActionInputRequested = "input.requested" - ActionRepositoryCreated = "repository.created" - ActionRepositoryUpdated = "repository.updated" - ActionRepositoryDeleted = "repository.deleted" - ActionRepositoryScriptCreated = "repository.script.created" - ActionRepositoryScriptUpdated = "repository.script.updated" - ActionRepositoryScriptDeleted = "repository.script.deleted" - ActionExecutorCreated = "executor.created" - ActionExecutorUpdated = "executor.updated" - ActionExecutorDeleted = "executor.deleted" - ActionEnvironmentCreated = "environment.created" - ActionEnvironmentUpdated = "environment.updated" - ActionEnvironmentDeleted = "environment.deleted" + ActionACPProgress = "acp.progress" + ActionACPLog = "acp.log" + ActionACPResult = "acp.result" + ActionACPError = "acp.error" + ActionACPStatus = "acp.status" + ActionACPHeartbeat = "acp.heartbeat" + ActionTaskCreated = "task.created" + ActionTaskUpdated = "task.updated" + ActionTaskDeleted = "task.deleted" + ActionTaskStateChanged = "task.state_changed" + ActionTaskPlanCreated = "task.plan.created" + ActionTaskPlanUpdated = "task.plan.updated" + ActionTaskPlanDeleted = "task.plan.deleted" + ActionAgentUpdated = "agent.updated" + ActionAgentAvailableUpdated = "agent.available.updated" + ActionWorkspaceCreated = "workspace.created" + ActionWorkspaceUpdated = "workspace.updated" + ActionWorkspaceDeleted = "workspace.deleted" + ActionWorkflowCreated = "workflow.created" + ActionWorkflowUpdated = "workflow.updated" + ActionWorkflowDeleted = "workflow.deleted" + ActionSessionMessageAdded = "session.message.added" + ActionSessionMessageUpdated = "session.message.updated" + ActionSessionStateChanged = "session.state_changed" + ActionSessionWaitingForInput = "session.waiting_for_input" + ActionSessionAgentctlStarting = "session.agentctl_starting" + ActionSessionAgentctlReady = "session.agentctl_ready" + ActionSessionAgentctlError = "session.agentctl_error" + ActionSessionTurnStarted = "session.turn.started" + ActionSessionTurnCompleted = "session.turn.completed" + ActionSessionAvailableCommands = "session.available_commands" + ActionInputRequested = "input.requested" + ActionRepositoryCreated = "repository.created" + ActionRepositoryUpdated = "repository.updated" + ActionRepositoryDeleted = "repository.deleted" + ActionRepositoryScriptCreated = "repository.script.created" + ActionRepositoryScriptUpdated = "repository.script.updated" + ActionRepositoryScriptDeleted = "repository.script.deleted" + ActionExecutorCreated = "executor.created" + ActionExecutorUpdated = "executor.updated" + ActionExecutorDeleted = "executor.deleted" + ActionEnvironmentCreated = "environment.created" + ActionEnvironmentUpdated = "environment.updated" + ActionEnvironmentDeleted = "environment.deleted" ActionAgentProfileDeleted = "agent.profile.deleted" ActionAgentProfileCreated = "agent.profile.created" diff --git a/apps/cli/README.md b/apps/cli/README.md index a20d6eea1d..6f161b32fe 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -21,16 +21,15 @@ Downloads the latest release, starts the backend + web app, and opens your brows ## Supported Agents -| Agent | Default Model | Protocol | -|-------|--------------|----------| -| **Claude Code** | Sonnet 4.5 | stream-json | -| **Codex** | GPT-5.2 Codex | Codex | -| **GitHub Copilot** | GPT-4.1 | Copilot SDK | -| **Gemini CLI** | Gemini 3 Flash | ACP | -| **Amp** | Smart Mode | stream-json | -| **Auggie** | Sonnet 4.5 | ACP | -| **OpenCode** | GPT-5 Nano | REST/SSE | - +| Agent | Default Model | Protocol | +| ------------------ | -------------- | ----------- | +| **Claude Code** | Sonnet 4.5 | stream-json | +| **Codex** | GPT-5.2 Codex | Codex | +| **GitHub Copilot** | GPT-4.1 | Copilot SDK | +| **Gemini CLI** | Gemini 3 Flash | ACP | +| **Amp** | Smart Mode | stream-json | +| **Auggie** | Sonnet 4.5 | ACP | +| **OpenCode** | GPT-5 Nano | REST/SSE | > **Beta** - Under active development. Expect rough edges and breaking changes. diff --git a/apps/cli/README_internal.md b/apps/cli/README_internal.md index 94d683f40a..9a9dc9eae2 100644 --- a/apps/cli/README_internal.md +++ b/apps/cli/README_internal.md @@ -24,6 +24,7 @@ flowchart TD ## Overview This package powers `npx kandev` by downloading prebuilt release bundles from GitHub Releases and running them locally. It: + - Detects OS/arch and fetches the matching bundle ZIP. - Verifies the SHA256 checksum when available. - Extracts the bundle into `~/.kandev/bin///`. @@ -35,11 +36,11 @@ It also supports local dev and production runs from a repo checkout. ## Commands -| Command | Description | -|---------|-------------| -| `kandev` or `kandev run` | Download and run release bundles (default) | -| `kandev dev` | Run local repo with hot-reload (requires repo checkout) | -| `kandev start` | Run local production build (requires `make build` first) | +| Command | Description | +| ------------------------ | -------------------------------------------------------- | +| `kandev` or `kandev run` | Download and run release bundles (default) | +| `kandev dev` | Run local repo with hot-reload (requires repo checkout) | +| `kandev start` | Run local production build (requires `make build` first) | ## Updates @@ -53,6 +54,7 @@ If you accept, it re-runs `npx kandev@latest` with the same arguments. This check is skipped in `dev` and `start` modes. Note: the runtime bundles are pulled from the latest GitHub Release by default, even if the CLI version is unchanged. So: + - **New runtime release without CLI publish**: users get new runtime automatically, but no update prompt. - **New CLI publish**: users get an update prompt and then re-run with the new CLI. @@ -87,15 +89,15 @@ pnpm -C apps/cli start ## CLI Options -| Option | Description | -|--------|-------------| -| `run` | Use release bundles (default) | -| `dev` | Use local repo with hot-reload | -| `start` | Use local production build | -| `--version ` | Release tag to install (default: latest) | -| `--backend-port ` | Override backend port | -| `--web-port ` | Override web port | -| `--help`, `-h` | Show help | +| Option | Description | +| ----------------------- | ---------------------------------------- | +| `run` | Use release bundles (default) | +| `dev` | Use local repo with hot-reload | +| `start` | Use local production build | +| `--version ` | Release tag to install (default: latest) | +| `--backend-port ` | Override backend port | +| `--web-port ` | Override web port | +| `--help`, `-h` | Show help | ## Local Development @@ -125,22 +127,22 @@ scripts/release/publish-launcher.sh 0.1.0 ## Environment Overrides -| Variable | Description | -|----------|-------------| -| `KANDEV_GITHUB_OWNER` | Override GitHub repo owner (default: `kandev`) | -| `KANDEV_GITHUB_REPO` | Override GitHub repo name (default: `kandev`) | -| `KANDEV_GITHUB_TOKEN` | Optional token for GitHub API rate limits | -| `KANDEV_NO_UPDATE_PROMPT=1` | Disable the CLI update prompt | -| `KANDEV_SKIP_UPDATE=1` | Internal guard to avoid update loops | -| `KANDEV_HEALTH_TIMEOUT_MS` | Override health check timeout in milliseconds | +| Variable | Description | +| --------------------------- | ---------------------------------------------- | +| `KANDEV_GITHUB_OWNER` | Override GitHub repo owner (default: `kandev`) | +| `KANDEV_GITHUB_REPO` | Override GitHub repo name (default: `kandev`) | +| `KANDEV_GITHUB_TOKEN` | Optional token for GitHub API rate limits | +| `KANDEV_NO_UPDATE_PROMPT=1` | Disable the CLI update prompt | +| `KANDEV_SKIP_UPDATE=1` | Internal guard to avoid update loops | +| `KANDEV_HEALTH_TIMEOUT_MS` | Override health check timeout in milliseconds | ## Supported Platforms -| Platform | Asset Name | -|----------|------------| -| macOS (Apple Silicon) | `kandev-macos-arm64.zip` | -| macOS (Intel) | `kandev-macos-x64.zip` | -| Linux (x64) | `kandev-linux-x64.zip` | -| Linux (ARM64) | `kandev-linux-arm64.zip` | -| Windows (x64) | `kandev-windows-x64.zip` | -| Windows (ARM64) | Falls back to `windows-x64` (x64 emulation) | +| Platform | Asset Name | +| --------------------- | ------------------------------------------- | +| macOS (Apple Silicon) | `kandev-macos-arm64.zip` | +| macOS (Intel) | `kandev-macos-x64.zip` | +| Linux (x64) | `kandev-linux-x64.zip` | +| Linux (ARM64) | `kandev-linux-arm64.zip` | +| Windows (x64) | `kandev-windows-x64.zip` | +| Windows (ARM64) | Falls back to `windows-x64` (x64 emulation) | diff --git a/apps/cli/src/dev.ts b/apps/cli/src/dev.ts index 1126d1105f..cbdee16b4f 100644 --- a/apps/cli/src/dev.ts +++ b/apps/cli/src/dev.ts @@ -30,11 +30,11 @@ export async function runDev({ repoRoot, backendPort, webPort }: DevOptions): Pr const supervisor = createProcessSupervisor(); supervisor.attachSignalHandlers(); - const backendProc = spawn( - "make", - ["-C", path.join("apps", "backend"), "dev"], - { cwd: repoRoot, env: backendEnv, stdio: "inherit" }, - ); + const backendProc = spawn("make", ["-C", path.join("apps", "backend"), "dev"], { + cwd: repoRoot, + env: backendEnv, + stdio: "inherit", + }); supervisor.children.push(backendProc); attachBackendExitHandler(backendProc, supervisor); diff --git a/apps/cli/src/platform.ts b/apps/cli/src/platform.ts index 7a9d670751..3e1102a5d8 100644 --- a/apps/cli/src/platform.ts +++ b/apps/cli/src/platform.ts @@ -3,12 +3,7 @@ import { execSync } from "node:child_process"; const isWindows = process.platform === "win32"; export type PlatformArch = "x64" | "arm64"; -export type PlatformDir = - | "linux-x64" - | "linux-arm64" - | "macos-x64" - | "macos-arm64" - | "windows-x64"; +export type PlatformDir = "linux-x64" | "linux-arm64" | "macos-x64" | "macos-arm64" | "windows-x64"; export function getBinaryName(base: string): string { return isWindows ? `${base}.exe` : base; diff --git a/apps/cli/src/shared.ts b/apps/cli/src/shared.ts index ffad6e9446..b66f7eab39 100644 --- a/apps/cli/src/shared.ts +++ b/apps/cli/src/shared.ts @@ -32,10 +32,7 @@ export type PortConfig = { * @param webPort - Optional preferred web port * @returns Resolved ports for all services */ -export async function pickPorts( - backendPort?: number, - webPort?: number, -): Promise { +export async function pickPorts(backendPort?: number, webPort?: number): Promise { const resolvedBackendPort = backendPort ?? (await pickAvailablePort(DEFAULT_BACKEND_PORT)); const resolvedWebPort = webPort ?? (await pickAvailablePort(DEFAULT_WEB_PORT)); const agentctlPort = await pickAvailablePort(DEFAULT_AGENTCTL_PORT); @@ -165,7 +162,7 @@ export function attachBackendExitHandler( ): void { backendProc.on("exit", (code, signal) => { console.error(`[kandev] backend exited (code=${code}, signal=${signal})`); - const exitCode = signal ? 0 : code ?? 1; + const exitCode = signal ? 0 : (code ?? 1); void supervisor.shutdown("backend exit").then(() => process.exit(exitCode)); }); } diff --git a/apps/cli/src/start.ts b/apps/cli/src/start.ts index 40772155ab..7a3f158bea 100644 --- a/apps/cli/src/start.ts +++ b/apps/cli/src/start.ts @@ -19,12 +19,7 @@ import { DATA_DIR, HEALTH_TIMEOUT_MS_RELEASE } from "./constants"; import { resolveHealthTimeoutMs, waitForHealth } from "./health"; import { getBinaryName } from "./platform"; import { createProcessSupervisor } from "./process"; -import { - attachBackendExitHandler, - buildBackendEnv, - buildWebEnv, - pickPorts, -} from "./shared"; +import { attachBackendExitHandler, buildBackendEnv, buildWebEnv, pickPorts } from "./shared"; import { launchWebApp } from "./web"; export type StartOptions = { @@ -68,7 +63,15 @@ export async function runStart({ } // Check for standalone build (Next.js standalone output) - const webServerPath = path.join(repoRoot, "apps", "web", ".next", "standalone", "web", "server.js"); + const webServerPath = path.join( + repoRoot, + "apps", + "web", + ".next", + "standalone", + "web", + "server.js", + ); if (!fs.existsSync(webServerPath)) { throw new Error("Web standalone build not found. Run `make build` first."); } diff --git a/apps/cli/src/update.ts b/apps/cli/src/update.ts index af85436d95..7e899ab4b3 100644 --- a/apps/cli/src/update.ts +++ b/apps/cli/src/update.ts @@ -4,24 +4,20 @@ import readline from "node:readline"; function requestJson(url: string): Promise { return new Promise((resolve, reject) => { - const req = https.get( - url, - { headers: { "User-Agent": "kandev-npx" } }, - (res) => { - if (res.statusCode !== 200) { - return reject(new Error(`HTTP ${res.statusCode} fetching ${url}`)); + const req = https.get(url, { headers: { "User-Agent": "kandev-npx" } }, (res) => { + if (res.statusCode !== 200) { + return reject(new Error(`HTTP ${res.statusCode} fetching ${url}`)); + } + let body = ""; + res.on("data", (chunk) => (body += chunk)); + res.on("end", () => { + try { + resolve(JSON.parse(body) as T); + } catch { + reject(new Error(`Failed to parse JSON from ${url}`)); } - let body = ""; - res.on("data", (chunk) => (body += chunk)); - res.on("end", () => { - try { - resolve(JSON.parse(body) as T); - } catch { - reject(new Error(`Failed to parse JSON from ${url}`)); - } - }); - }, - ); + }); + }); req.setTimeout(5000, () => { req.destroy(new Error(`Request timed out fetching ${url}`)); }); @@ -61,7 +57,9 @@ function promptYesNo(question: string, defaultYes = false): Promise { const suffix = defaultYes ? "[Y/n]" : "[y/N]"; rl.question(`${question} ${suffix} `, (answer: string) => { rl.close(); - const normalized = String(answer || "").trim().toLowerCase(); + const normalized = String(answer || "") + .trim() + .toLowerCase(); if (!normalized) { resolve(Boolean(defaultYes)); return; diff --git a/apps/cli/src/web.ts b/apps/cli/src/web.ts index 410a841a66..3887dcfcbe 100644 --- a/apps/cli/src/web.ts +++ b/apps/cli/src/web.ts @@ -7,9 +7,7 @@ let _isWSL: boolean | undefined; function isWSL(): boolean { if (_isWSL === undefined) { try { - _isWSL = readFileSync("/proc/version", "utf8") - .toLowerCase() - .includes("microsoft"); + _isWSL = readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft"); } catch { _isWSL = false; } @@ -34,12 +32,7 @@ export function openBrowser(url: string) { return; } const useCmd = process.platform === "win32" || isWSL(); - const opener = - process.platform === "darwin" - ? "open" - : useCmd - ? "cmd.exe" - : "xdg-open"; + const opener = process.platform === "darwin" ? "open" : useCmd ? "cmd.exe" : "xdg-open"; const args = useCmd ? ["/c", "start", "", url] : [url]; try { const child = spawn(opener, args, { stdio: "ignore", detached: true }); @@ -71,7 +64,7 @@ export function launchWebApp({ proc.on("exit", (code, signal) => { console.error(`[kandev] ${label} exited (code=${code}, signal=${signal})`); - const exitCode = signal ? 0 : code ?? 1; + const exitCode = signal ? 0 : (code ?? 1); void supervisor.shutdown(`${label} exit`).then(() => process.exit(exitCode)); }); diff --git a/apps/package.json b/apps/package.json index 365cb49eed..0bea53b65b 100644 --- a/apps/package.json +++ b/apps/package.json @@ -8,10 +8,13 @@ "build": "pnpm -r run build", "build:web": "pnpm --filter @kandev/web build", "lint": "pnpm -r run lint", + "format": "prettier --write web cli packages --ignore-unknown", + "format:check": "prettier --check web cli packages --ignore-unknown", "clean": "pnpm -r run clean && rm -rf node_modules" }, "devDependencies": { "@types/node": "^20", + "prettier": "^3.6.2", "typescript": "^5" }, "pnpm": { diff --git a/apps/packages/theme/src/fonts.css b/apps/packages/theme/src/fonts.css index d2bd494ff2..4ea474ef86 100644 --- a/apps/packages/theme/src/fonts.css +++ b/apps/packages/theme/src/fonts.css @@ -1,78 +1,93 @@ @font-face { - font-family: 'Figtree'; + font-family: "Figtree"; font-style: normal; font-weight: 300 900; font-display: swap; - src: url('/fonts/figtree/figtree-300-normal.woff2') format('woff2'); - unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; + src: url("/fonts/figtree/figtree-300-normal.woff2") format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, + U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, + U+A720-A7FF; } @font-face { - font-family: 'Figtree'; + font-family: "Figtree"; font-style: normal; font-weight: 300 900; font-display: swap; - src: url('/fonts/figtree/figtree-300-normal.woff2') format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: url("/fonts/figtree/figtree-300-normal.woff2") format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { - font-family: 'Geist'; + font-family: "Geist"; font-style: normal; font-weight: 100 900; font-display: swap; - src: url('/fonts/geist/geist-100-normal.woff2') format('woff2'); + src: url("/fonts/geist/geist-100-normal.woff2") format("woff2"); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { - font-family: 'Geist'; + font-family: "Geist"; font-style: normal; font-weight: 100 900; font-display: swap; - src: url('/fonts/geist/geist-100-normal.woff2') format('woff2'); - unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; + src: url("/fonts/geist/geist-100-normal.woff2") format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, + U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, + U+A720-A7FF; } @font-face { - font-family: 'Geist'; + font-family: "Geist"; font-style: normal; font-weight: 100 900; font-display: swap; - src: url('/fonts/geist/geist-100-normal.woff2') format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: url("/fonts/geist/geist-100-normal.woff2") format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { - font-family: 'Geist Mono'; + font-family: "Geist Mono"; font-style: normal; font-weight: 100 900; font-display: swap; - src: url('/fonts/geist-mono/geist-mono-100-normal.woff2') format('woff2'); + src: url("/fonts/geist-mono/geist-mono-100-normal.woff2") format("woff2"); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { - font-family: 'Geist Mono'; + font-family: "Geist Mono"; font-style: normal; font-weight: 100 900; font-display: swap; - src: url('/fonts/geist-mono/geist-mono-100-normal.woff2') format('woff2'); - unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; + src: url("/fonts/geist-mono/geist-mono-100-normal.woff2") format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, + U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, + U+A720-A7FF; } @font-face { - font-family: 'Geist Mono'; + font-family: "Geist Mono"; font-style: normal; font-weight: 100 900; font-display: swap; - src: url('/fonts/geist-mono/geist-mono-100-normal.woff2') format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: url("/fonts/geist-mono/geist-mono-100-normal.woff2") format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { - font-family: 'Seti'; - src: url('/fonts/seti/seti.woff') format('woff'); + font-family: "Seti"; + src: url("/fonts/seti/seti.woff") format("woff"); font-weight: normal; font-style: normal; font-display: swap; diff --git a/apps/packages/theme/src/globals.css b/apps/packages/theme/src/globals.css index e9f9225c68..7a733acbea 100644 --- a/apps/packages/theme/src/globals.css +++ b/apps/packages/theme/src/globals.css @@ -49,10 +49,10 @@ :root { --font-geist-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; - --font-sans: "Figtree", "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", - sans-serif; - --font-geist-mono: "Geist Mono", ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, - "Liberation Mono", "Courier New", monospace; + --font-sans: "Figtree", "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; + --font-geist-mono: + "Geist Mono", ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); @@ -71,9 +71,9 @@ --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); - --chart-1: oklch(0.79 0.10 275); + --chart-1: oklch(0.79 0.1 275); --chart-2: oklch(0.68 0.16 277); - --chart-3: oklch(0.59 0.20 277); + --chart-3: oklch(0.59 0.2 277); --chart-4: oklch(0.51 0.23 277); --chart-5: oklch(0.46 0.21 277); --radius: 0.375rem; @@ -94,7 +94,7 @@ --card-foreground: oklch(0.985 0 0); --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.59 0.20 277); + --primary: oklch(0.59 0.2 277); --primary-foreground: oklch(0.96 0.02 272); --secondary: oklch(0.274 0.006 286.033); --secondary-foreground: oklch(0.985 0 0); @@ -106,9 +106,9 @@ --border: oklch(1 0 0 / 10%); --input: oklch(1 0 0 / 15%); --ring: oklch(0.556 0 0); - --chart-1: oklch(0.79 0.10 275); + --chart-1: oklch(0.79 0.1 275); --chart-2: oklch(0.68 0.16 277); - --chart-3: oklch(0.59 0.20 277); + --chart-3: oklch(0.59 0.2 277); --chart-4: oklch(0.51 0.23 277); --chart-5: oklch(0.46 0.21 277); --sidebar: oklch(0.205 0 0); diff --git a/apps/packages/types/src/backend.ts b/apps/packages/types/src/backend.ts index 9b151a6a56..8b2a10cadd 100644 --- a/apps/packages/types/src/backend.ts +++ b/apps/packages/types/src/backend.ts @@ -1,27 +1,27 @@ export type BackendMessageType = - | 'kanban.update' - | 'task.created' - | 'task.updated' - | 'task.deleted' - | 'task.state_changed' - | 'agent.updated' - | 'terminal.output' - | 'diff.update' - | 'system.error' - | 'workspace.created' - | 'workspace.updated' - | 'workspace.deleted' - | 'board.created' - | 'board.updated' - | 'board.deleted' - | 'column.created' - | 'column.updated' - | 'column.deleted' - | 'task_session.waiting_for_input'; + | "kanban.update" + | "task.created" + | "task.updated" + | "task.deleted" + | "task.state_changed" + | "agent.updated" + | "terminal.output" + | "diff.update" + | "system.error" + | "workspace.created" + | "workspace.updated" + | "workspace.deleted" + | "board.created" + | "board.updated" + | "board.deleted" + | "column.created" + | "column.updated" + | "column.deleted" + | "task_session.waiting_for_input"; export type BackendMessage = { id?: string; - type: 'request' | 'response' | 'notification' | 'error'; + type: "request" | "response" | "notification" | "error"; action: T; payload: P; timestamp?: string; @@ -53,21 +53,21 @@ export type TaskEventPayload = { export type AgentUpdatePayload = { agentId: string; - status: 'idle' | 'running' | 'error'; + status: "idle" | "running" | "error"; message?: string; }; export type TerminalOutputPayload = { terminalId: string; data: string; - stream?: 'stdout' | 'stderr'; + stream?: "stdout" | "stderr"; }; export type DiffUpdatePayload = { taskId: string; files: Array<{ path: string; - status: 'A' | 'M' | 'D'; + status: "A" | "M" | "D"; plus: number; minus: number; }>; @@ -115,26 +115,26 @@ export type ColumnPayload = { }; export type BackendMessageMap = { - 'kanban.update': BackendMessage<'kanban.update', KanbanUpdatePayload>; - 'task.created': BackendMessage<'task.created', TaskEventPayload>; - 'task.updated': BackendMessage<'task.updated', TaskEventPayload>; - 'task.deleted': BackendMessage<'task.deleted', TaskEventPayload>; - 'task.state_changed': BackendMessage<'task.state_changed', TaskEventPayload>; - 'agent.updated': BackendMessage<'agent.updated', AgentUpdatePayload>; - 'terminal.output': BackendMessage<'terminal.output', TerminalOutputPayload>; - 'diff.update': BackendMessage<'diff.update', DiffUpdatePayload>; - 'system.error': BackendMessage<'system.error', SystemErrorPayload>; - 'workspace.created': BackendMessage<'workspace.created', WorkspacePayload>; - 'workspace.updated': BackendMessage<'workspace.updated', WorkspacePayload>; - 'workspace.deleted': BackendMessage<'workspace.deleted', WorkspacePayload>; - 'board.created': BackendMessage<'board.created', BoardPayload>; - 'board.updated': BackendMessage<'board.updated', BoardPayload>; - 'board.deleted': BackendMessage<'board.deleted', BoardPayload>; - 'column.created': BackendMessage<'column.created', ColumnPayload>; - 'column.updated': BackendMessage<'column.updated', ColumnPayload>; - 'column.deleted': BackendMessage<'column.deleted', ColumnPayload>; - 'task_session.waiting_for_input': BackendMessage< - 'task_session.waiting_for_input', + "kanban.update": BackendMessage<"kanban.update", KanbanUpdatePayload>; + "task.created": BackendMessage<"task.created", TaskEventPayload>; + "task.updated": BackendMessage<"task.updated", TaskEventPayload>; + "task.deleted": BackendMessage<"task.deleted", TaskEventPayload>; + "task.state_changed": BackendMessage<"task.state_changed", TaskEventPayload>; + "agent.updated": BackendMessage<"agent.updated", AgentUpdatePayload>; + "terminal.output": BackendMessage<"terminal.output", TerminalOutputPayload>; + "diff.update": BackendMessage<"diff.update", DiffUpdatePayload>; + "system.error": BackendMessage<"system.error", SystemErrorPayload>; + "workspace.created": BackendMessage<"workspace.created", WorkspacePayload>; + "workspace.updated": BackendMessage<"workspace.updated", WorkspacePayload>; + "workspace.deleted": BackendMessage<"workspace.deleted", WorkspacePayload>; + "board.created": BackendMessage<"board.created", BoardPayload>; + "board.updated": BackendMessage<"board.updated", BoardPayload>; + "board.deleted": BackendMessage<"board.deleted", BoardPayload>; + "column.created": BackendMessage<"column.created", ColumnPayload>; + "column.updated": BackendMessage<"column.updated", ColumnPayload>; + "column.deleted": BackendMessage<"column.deleted", ColumnPayload>; + "task_session.waiting_for_input": BackendMessage< + "task_session.waiting_for_input", TaskSessionWaitingForInputPayload >; }; diff --git a/apps/packages/types/src/http.ts b/apps/packages/types/src/http.ts index 57151adfae..ac356529d2 100644 --- a/apps/packages/types/src/http.ts +++ b/apps/packages/types/src/http.ts @@ -1,14 +1,14 @@ export type TaskState = - | 'CREATED' - | 'SCHEDULING' - | 'TODO' - | 'IN_PROGRESS' - | 'REVIEW' - | 'BLOCKED' - | 'WAITING_FOR_INPUT' - | 'COMPLETED' - | 'FAILED' - | 'CANCELLED'; + | "CREATED" + | "SCHEDULING" + | "TODO" + | "IN_PROGRESS" + | "REVIEW" + | "BLOCKED" + | "WAITING_FOR_INPUT" + | "COMPLETED" + | "FAILED" + | "CANCELLED"; export type Board = { id: string; diff --git a/apps/packages/types/src/index.ts b/apps/packages/types/src/index.ts index 6a8e7f9a3e..77b337e6e1 100644 --- a/apps/packages/types/src/index.ts +++ b/apps/packages/types/src/index.ts @@ -1,2 +1,2 @@ -export * from './backend'; -export * from './http'; +export * from "./backend"; +export * from "./http"; diff --git a/apps/packages/ui/src/accordion.tsx b/apps/packages/ui/src/accordion.tsx index 81427895fe..c5a88dc097 100644 --- a/apps/packages/ui/src/accordion.tsx +++ b/apps/packages/ui/src/accordion.tsx @@ -1,22 +1,19 @@ -"use client" +"use client"; -import * as React from "react" -import { Accordion as AccordionPrimitive } from "radix-ui" +import * as React from "react"; +import { Accordion as AccordionPrimitive } from "radix-ui"; -import { cn } from "./lib/utils" -import { IconChevronDown, IconChevronUp } from "@tabler/icons-react" +import { cn } from "./lib/utils"; +import { IconChevronDown, IconChevronUp } from "@tabler/icons-react"; -function Accordion({ - className, - ...props -}: React.ComponentProps) { +function Accordion({ className, ...props }: React.ComponentProps) { return ( - ) + ); } function AccordionItem({ @@ -29,7 +26,7 @@ function AccordionItem({ className={cn("data-open:bg-muted/50 not-last:border-b", className)} {...props} /> - ) + ); } function AccordionTrigger({ @@ -43,16 +40,22 @@ function AccordionTrigger({ data-slot="accordion-trigger" className={cn( "**:data-[slot=accordion-trigger-icon]:text-muted-foreground gap-6 p-2 text-left text-xs/relaxed font-medium hover:underline **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 group/accordion-trigger relative flex flex-1 items-start justify-between border border-transparent transition-all outline-none disabled:pointer-events-none disabled:opacity-50", - className + className, )} {...props} > {children} - - + + - ) + ); } function AccordionContent({ @@ -69,13 +72,13 @@ function AccordionContent({
{children}
- ) + ); } -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/apps/packages/ui/src/alert-dialog.tsx b/apps/packages/ui/src/alert-dialog.tsx index 3835fa48ac..feccd8d1ef 100644 --- a/apps/packages/ui/src/alert-dialog.tsx +++ b/apps/packages/ui/src/alert-dialog.tsx @@ -1,31 +1,23 @@ -"use client" +"use client"; -import * as React from "react" -import { AlertDialog as AlertDialogPrimitive } from "radix-ui" +import * as React from "react"; +import { AlertDialog as AlertDialogPrimitive } from "radix-ui"; -import { cn } from "./lib/utils" -import { Button } from "./button" +import { cn } from "./lib/utils"; +import { Button } from "./button"; -function AlertDialog({ - ...props -}: React.ComponentProps) { - return +function AlertDialog({ ...props }: React.ComponentProps) { + return ; } function AlertDialogTrigger({ ...props }: React.ComponentProps) { - return ( - - ) + return ; } -function AlertDialogPortal({ - ...props -}: React.ComponentProps) { - return ( - - ) +function AlertDialogPortal({ ...props }: React.ComponentProps) { + return ; } function AlertDialogOverlay({ @@ -35,10 +27,13 @@ function AlertDialogOverlay({ return ( - ) + ); } function AlertDialogContent({ @@ -46,7 +41,7 @@ function AlertDialogContent({ size = "default", ...props }: React.ComponentProps & { - size?: "default" | "sm" + size?: "default" | "sm"; }) { return ( @@ -56,54 +51,51 @@ function AlertDialogContent({ data-size={size} className={cn( "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-background ring-foreground/10 gap-3 rounded-xl p-4 ring-1 duration-100 data-[size=default]:max-w-xs data-[size=sm]:max-w-64 data-[size=default]:sm:max-w-sm group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 outline-none", - className + className, )} {...props} /> - ) + ); } -function AlertDialogHeader({ - className, - ...props -}: React.ComponentProps<"div">) { +function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">) { return (
- ) + ); } -function AlertDialogFooter({ - className, - ...props -}: React.ComponentProps<"div">) { +function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">) { return (
- ) + ); } -function AlertDialogMedia({ - className, - ...props -}: React.ComponentProps<"div">) { +function AlertDialogMedia({ className, ...props }: React.ComponentProps<"div">) { return (
- ) + ); } function AlertDialogTitle({ @@ -113,10 +105,13 @@ function AlertDialogTitle({ return ( - ) + ); } function AlertDialogDescription({ @@ -126,10 +121,13 @@ function AlertDialogDescription({ return ( - ) + ); } function AlertDialogAction({ @@ -147,7 +145,7 @@ function AlertDialogAction({ {...props} /> - ) + ); } function AlertDialogCancel({ @@ -165,7 +163,7 @@ function AlertDialogCancel({ {...props} /> - ) + ); } export { @@ -181,4 +179,4 @@ export { AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, -} +}; diff --git a/apps/packages/ui/src/alert.tsx b/apps/packages/ui/src/alert.tsx index aecc9e641d..93d3835030 100644 --- a/apps/packages/ui/src/alert.tsx +++ b/apps/packages/ui/src/alert.tsx @@ -1,19 +1,23 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "./lib/utils" +import { cn } from "./lib/utils"; -const alertVariants = cva("grid gap-0.5 rounded-lg border px-2 py-1.5 text-left text-xs/relaxed has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-1.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-3.5 w-full relative group/alert", { - variants: { - variant: { - default: "bg-card text-card-foreground", - destructive: "text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current", +const alertVariants = cva( + "grid gap-0.5 rounded-lg border px-2 py-1.5 text-left text-xs/relaxed has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-1.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-3.5 w-full relative group/alert", + { + variants: { + variant: { + default: "bg-card text-card-foreground", + destructive: + "text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current", + }, + }, + defaultVariants: { + variant: "default", }, }, - defaultVariants: { - variant: "default", - }, -}) +); function Alert({ className, @@ -27,7 +31,7 @@ function Alert({ className={cn(alertVariants({ variant }), className)} {...props} /> - ) + ); } function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { @@ -36,27 +40,24 @@ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { data-slot="alert-title" className={cn( "font-medium group-has-[>svg]/alert:col-start-2 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3", - className + className, )} {...props} /> - ) + ); } -function AlertDescription({ - className, - ...props -}: React.ComponentProps<"div">) { +function AlertDescription({ className, ...props }: React.ComponentProps<"div">) { return (
- ) + ); } function AlertAction({ className, ...props }: React.ComponentProps<"div">) { @@ -66,7 +67,7 @@ function AlertAction({ className, ...props }: React.ComponentProps<"div">) { className={cn("absolute top-1.5 right-2", className)} {...props} /> - ) + ); } -export { Alert, AlertTitle, AlertDescription, AlertAction } +export { Alert, AlertTitle, AlertDescription, AlertAction }; diff --git a/apps/packages/ui/src/aspect-ratio.tsx b/apps/packages/ui/src/aspect-ratio.tsx index 57e38fa96f..b5993d1e45 100644 --- a/apps/packages/ui/src/aspect-ratio.tsx +++ b/apps/packages/ui/src/aspect-ratio.tsx @@ -1,11 +1,9 @@ -"use client" +"use client"; -import { AspectRatio as AspectRatioPrimitive } from "radix-ui" +import { AspectRatio as AspectRatioPrimitive } from "radix-ui"; -function AspectRatio({ - ...props -}: React.ComponentProps) { - return +function AspectRatio({ ...props }: React.ComponentProps) { + return ; } -export { AspectRatio } +export { AspectRatio }; diff --git a/apps/packages/ui/src/avatar.tsx b/apps/packages/ui/src/avatar.tsx index d5700e7c5b..7d314191fe 100644 --- a/apps/packages/ui/src/avatar.tsx +++ b/apps/packages/ui/src/avatar.tsx @@ -1,16 +1,16 @@ -"use client" +"use client"; -import * as React from "react" -import { Avatar as AvatarPrimitive } from "radix-ui" +import * as React from "react"; +import { Avatar as AvatarPrimitive } from "radix-ui"; -import { cn } from "./lib/utils" +import { cn } from "./lib/utils"; function Avatar({ className, size = "default", ...props }: React.ComponentProps & { - size?: "default" | "sm" | "lg" + size?: "default" | "sm" | "lg"; }) { return ( - ) + ); } -function AvatarImage({ - className, - ...props -}: React.ComponentProps) { +function AvatarImage({ className, ...props }: React.ComponentProps) { return ( - ) + ); } function AvatarFallback({ @@ -50,11 +44,11 @@ function AvatarFallback({ data-slot="avatar-fallback" className={cn( "bg-muted text-muted-foreground rounded-full flex size-full items-center justify-center text-sm group-data-[size=sm]/avatar:text-xs", - className + className, )} {...props} /> - ) + ); } function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) { @@ -66,11 +60,11 @@ function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) { "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden", "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", - className + className, )} {...props} /> - ) + ); } function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) { @@ -79,31 +73,24 @@ function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) { data-slot="avatar-group" className={cn( "*:data-[slot=avatar]:ring-background group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2", - className + className, )} {...props} /> - ) + ); } -function AvatarGroupCount({ - className, - ...props -}: React.ComponentProps<"div">) { +function AvatarGroupCount({ className, ...props }: React.ComponentProps<"div">) { return (
svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3 ring-background relative flex shrink-0 items-center justify-center ring-2", className)} + className={cn( + "bg-muted text-muted-foreground size-8 rounded-full text-xs/relaxed group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3 ring-background relative flex shrink-0 items-center justify-center ring-2", + className, + )} {...props} /> - ) + ); } -export { - Avatar, - AvatarImage, - AvatarFallback, - AvatarGroup, - AvatarGroupCount, - AvatarBadge, -} +export { Avatar, AvatarImage, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarBadge }; diff --git a/apps/packages/ui/src/badge.tsx b/apps/packages/ui/src/badge.tsx index f5db89759d..9ac729eb0e 100644 --- a/apps/packages/ui/src/badge.tsx +++ b/apps/packages/ui/src/badge.tsx @@ -1,8 +1,8 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" -import { Slot } from "radix-ui" +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; +import { Slot } from "radix-ui"; -import { cn } from "./lib/utils" +import { cn } from "./lib/utils"; const badgeVariants = cva( "h-5 gap-1 rounded-full border border-transparent px-2 py-0.5 text-[0.625rem] font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-2.5! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge", @@ -11,8 +11,10 @@ const badgeVariants = cva( variant: { default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80", - destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20", - outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground bg-input/20 dark:bg-input/30", + destructive: + "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20", + outline: + "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground bg-input/20 dark:bg-input/30", ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50", link: "text-primary underline-offset-4 hover:underline", }, @@ -20,17 +22,16 @@ const badgeVariants = cva( defaultVariants: { variant: "default", }, - } -) + }, +); function Badge({ className, variant = "default", asChild = false, ...props -}: React.ComponentProps<"span"> & - VariantProps & { asChild?: boolean }) { - const Comp = asChild ? Slot.Root : "span" +}: React.ComponentProps<"span"> & VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot.Root : "span"; return ( - ) + ); } -export { Badge, badgeVariants } +export { Badge, badgeVariants }; diff --git a/apps/packages/ui/src/breadcrumb.tsx b/apps/packages/ui/src/breadcrumb.tsx index 667e7d6b8b..742e159850 100644 --- a/apps/packages/ui/src/breadcrumb.tsx +++ b/apps/packages/ui/src/breadcrumb.tsx @@ -1,18 +1,13 @@ -import * as React from "react" -import { Slot } from "radix-ui" +import * as React from "react"; +import { Slot } from "radix-ui"; -import { cn } from "./lib/utils" -import { IconChevronRight, IconDots } from "@tabler/icons-react" +import { cn } from "./lib/utils"; +import { IconChevronRight, IconDots } from "@tabler/icons-react"; function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) { return ( -
- ) + ); } -function CommandList({ - className, - ...props -}: React.ComponentProps) { +function CommandList({ className, ...props }: React.ComponentProps) { return ( - ) + ); } function CommandEmpty({ @@ -114,7 +99,7 @@ function CommandEmpty({ className={cn("py-6 text-center text-xs/relaxed", className)} {...props} /> - ) + ); } function CommandGroup({ @@ -124,10 +109,13 @@ function CommandGroup({ return ( - ) + ); } function CommandSeparator({ @@ -140,7 +128,7 @@ function CommandSeparator({ className={cn("bg-border/50 -mx-1 my-1 h-px", className)} {...props} /> - ) + ); } function CommandItem({ @@ -153,27 +141,27 @@ function CommandItem({ data-slot="command-item" className={cn( "data-selected:bg-muted data-selected:text-foreground data-selected:*:[svg]:text-foreground relative flex min-h-7 cursor-default items-center gap-2 rounded-md px-2.5 py-1.5 text-xs/relaxed outline-hidden select-none [&_svg:not([class*='size-'])]:size-3.5 [[data-slot=dialog-content]_&]:rounded-md group/command-item data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", - className + className, )} {...props} > {children} - ) + ); } -function CommandShortcut({ - className, - ...props -}: React.ComponentProps<"span">) { +function CommandShortcut({ className, ...props }: React.ComponentProps<"span">) { return ( - ) + ); } export { @@ -186,4 +174,4 @@ export { CommandItem, CommandShortcut, CommandSeparator, -} +}; diff --git a/apps/packages/ui/src/context-menu.tsx b/apps/packages/ui/src/context-menu.tsx index 99f281af95..506f7cf6ad 100644 --- a/apps/packages/ui/src/context-menu.tsx +++ b/apps/packages/ui/src/context-menu.tsx @@ -1,15 +1,13 @@ -"use client" +"use client"; -import * as React from "react" -import { ContextMenu as ContextMenuPrimitive } from "radix-ui" +import * as React from "react"; +import { ContextMenu as ContextMenuPrimitive } from "radix-ui"; -import { cn } from "./lib/utils" -import { IconChevronRight, IconCheck } from "@tabler/icons-react" +import { cn } from "./lib/utils"; +import { IconChevronRight, IconCheck } from "@tabler/icons-react"; -function ContextMenu({ - ...props -}: React.ComponentProps) { - return +function ContextMenu({ ...props }: React.ComponentProps) { + return ; } function ContextMenuTrigger({ @@ -22,57 +20,45 @@ function ContextMenuTrigger({ className={cn("select-none", className)} {...props} /> - ) + ); } -function ContextMenuGroup({ - ...props -}: React.ComponentProps) { - return ( - - ) +function ContextMenuGroup({ ...props }: React.ComponentProps) { + return ; } -function ContextMenuPortal({ - ...props -}: React.ComponentProps) { - return ( - - ) +function ContextMenuPortal({ ...props }: React.ComponentProps) { + return ; } -function ContextMenuSub({ - ...props -}: React.ComponentProps) { - return +function ContextMenuSub({ ...props }: React.ComponentProps) { + return ; } function ContextMenuRadioGroup({ ...props }: React.ComponentProps) { - return ( - - ) + return ; } function ContextMenuContent({ className, ...props }: React.ComponentProps & { - side?: "top" | "right" | "bottom" | "left" + side?: "top" | "right" | "bottom" | "left"; }) { return ( - ) + ); } function ContextMenuItem({ @@ -81,8 +67,8 @@ function ContextMenuItem({ variant = "default", ...props }: React.ComponentProps & { - inset?: boolean - variant?: "default" | "destructive" + inset?: boolean; + variant?: "default" | "destructive"; }) { return ( - ) + ); } function ContextMenuSubTrigger({ @@ -104,7 +90,7 @@ function ContextMenuSubTrigger({ children, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( {children} - ) + ); } function ContextMenuSubContent({ @@ -129,10 +115,13 @@ function ContextMenuSubContent({ return ( - ) + ); } function ContextMenuCheckboxItem({ @@ -146,20 +135,19 @@ function ContextMenuCheckboxItem({ data-slot="context-menu-checkbox-item" className={cn( "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground min-h-7 gap-2 rounded-md py-1.5 pr-8 pl-2 text-xs [&_svg:not([class*='size-'])]:size-3.5 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", - className + className, )} checked={checked} {...props} > - + {children} - ) + ); } function ContextMenuRadioItem({ @@ -172,19 +160,18 @@ function ContextMenuRadioItem({ data-slot="context-menu-radio-item" className={cn( "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground min-h-7 gap-2 rounded-md py-1.5 pr-8 pl-2 text-xs [&_svg:not([class*='size-'])]:size-3.5 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", - className + className, )} {...props} > - + {children} - ) + ); } function ContextMenuLabel({ @@ -192,7 +179,7 @@ function ContextMenuLabel({ inset, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( - ) + ); } function ContextMenuSeparator({ @@ -214,20 +201,20 @@ function ContextMenuSeparator({ className={cn("bg-border/50 -mx-1 my-1 h-px", className)} {...props} /> - ) + ); } -function ContextMenuShortcut({ - className, - ...props -}: React.ComponentProps<"span">) { +function ContextMenuShortcut({ className, ...props }: React.ComponentProps<"span">) { return ( - ) + ); } export { @@ -246,4 +233,4 @@ export { ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuRadioGroup, -} +}; diff --git a/apps/packages/ui/src/dialog.tsx b/apps/packages/ui/src/dialog.tsx index e46dcd5856..4b425fd85b 100644 --- a/apps/packages/ui/src/dialog.tsx +++ b/apps/packages/ui/src/dialog.tsx @@ -1,34 +1,26 @@ -"use client" +"use client"; -import * as React from "react" -import { Dialog as DialogPrimitive } from "radix-ui" +import * as React from "react"; +import { Dialog as DialogPrimitive } from "radix-ui"; -import { cn } from "./lib/utils" -import { Button } from "./button" -import { IconX } from "@tabler/icons-react" +import { cn } from "./lib/utils"; +import { Button } from "./button"; +import { IconX } from "@tabler/icons-react"; -function Dialog({ - ...props -}: React.ComponentProps) { - return +function Dialog({ ...props }: React.ComponentProps) { + return ; } -function DialogTrigger({ - ...props -}: React.ComponentProps) { - return +function DialogTrigger({ ...props }: React.ComponentProps) { + return ; } -function DialogPortal({ - ...props -}: React.ComponentProps) { - return +function DialogPortal({ ...props }: React.ComponentProps) { + return ; } -function DialogClose({ - ...props -}: React.ComponentProps) { - return +function DialogClose({ ...props }: React.ComponentProps) { + return ; } function DialogOverlay({ @@ -38,10 +30,13 @@ function DialogOverlay({ return ( - ) + ); } function DialogContent({ @@ -51,8 +46,8 @@ function DialogContent({ overlayClassName, ...props }: React.ComponentProps & { - showCloseButton?: boolean - overlayClassName?: string + showCloseButton?: boolean; + overlayClassName?: string; }) { return ( @@ -61,7 +56,7 @@ function DialogContent({ data-slot="dialog-content" className={cn( "bg-card data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-xs/relaxed ring-1 duration-100 sm:max-w-lg fixed top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2", - className + className, )} {...props} > @@ -69,25 +64,20 @@ function DialogContent({ {showCloseButton && ( )} - ) + ); } function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { return ( -
- ) +
+ ); } function DialogFooter({ @@ -96,15 +86,12 @@ function DialogFooter({ children, ...props }: React.ComponentProps<"div"> & { - showCloseButton?: boolean + showCloseButton?: boolean; }) { return (
{children} @@ -114,20 +101,17 @@ function DialogFooter({ )}
- ) + ); } -function DialogTitle({ - className, - ...props -}: React.ComponentProps) { +function DialogTitle({ className, ...props }: React.ComponentProps) { return ( - ) + ); } function DialogDescription({ @@ -137,10 +121,13 @@ function DialogDescription({ return ( - ) + ); } export { @@ -154,4 +141,4 @@ export { DialogPortal, DialogTitle, DialogTrigger, -} +}; diff --git a/apps/packages/ui/src/drawer.tsx b/apps/packages/ui/src/drawer.tsx index e0c86141e7..2450a1ccde 100644 --- a/apps/packages/ui/src/drawer.tsx +++ b/apps/packages/ui/src/drawer.tsx @@ -1,32 +1,24 @@ -"use client" +"use client"; -import * as React from "react" -import { Drawer as DrawerPrimitive } from "vaul" +import * as React from "react"; +import { Drawer as DrawerPrimitive } from "vaul"; -import { cn } from "./lib/utils" +import { cn } from "./lib/utils"; -function Drawer({ - ...props -}: React.ComponentProps) { - return +function Drawer({ ...props }: React.ComponentProps) { + return ; } -function DrawerTrigger({ - ...props -}: React.ComponentProps) { - return +function DrawerTrigger({ ...props }: React.ComponentProps) { + return ; } -function DrawerPortal({ - ...props -}: React.ComponentProps) { - return +function DrawerPortal({ ...props }: React.ComponentProps) { + return ; } -function DrawerClose({ - ...props -}: React.ComponentProps) { - return +function DrawerClose({ ...props }: React.ComponentProps) { + return ; } function DrawerOverlay({ @@ -36,10 +28,13 @@ function DrawerOverlay({ return ( - ) + ); } function DrawerContent({ @@ -54,7 +49,7 @@ function DrawerContent({ data-slot="drawer-content" className={cn( "before:bg-background relative flex h-auto flex-col bg-transparent p-2 text-xs/relaxed before:absolute before:inset-2 before:-z-10 before:rounded-xl data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50", - className + className, )} {...props} > @@ -62,17 +57,20 @@ function DrawerContent({ {children} - ) + ); } function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) { return (
- ) + ); } function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) { @@ -82,20 +80,17 @@ function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) { className={cn("gap-2 p-4 mt-auto flex flex-col", className)} {...props} /> - ) + ); } -function DrawerTitle({ - className, - ...props -}: React.ComponentProps) { +function DrawerTitle({ className, ...props }: React.ComponentProps) { return ( - ) + ); } function DrawerDescription({ @@ -108,7 +103,7 @@ function DrawerDescription({ className={cn("text-muted-foreground text-xs/relaxed", className)} {...props} /> - ) + ); } export { @@ -122,4 +117,4 @@ export { DrawerFooter, DrawerTitle, DrawerDescription, -} +}; diff --git a/apps/packages/ui/src/dropdown-menu.tsx b/apps/packages/ui/src/dropdown-menu.tsx index 2a38dd907c..dbd4d395ef 100644 --- a/apps/packages/ui/src/dropdown-menu.tsx +++ b/apps/packages/ui/src/dropdown-menu.tsx @@ -1,34 +1,25 @@ -"use client" +"use client"; -import * as React from "react" -import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui" +import * as React from "react"; +import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"; -import { cn } from "./lib/utils" -import { IconCheck, IconChevronRight } from "@tabler/icons-react" +import { cn } from "./lib/utils"; +import { IconCheck, IconChevronRight } from "@tabler/icons-react"; -function DropdownMenu({ - ...props -}: React.ComponentProps) { - return +function DropdownMenu({ ...props }: React.ComponentProps) { + return ; } function DropdownMenuPortal({ ...props }: React.ComponentProps) { - return ( - - ) + return ; } function DropdownMenuTrigger({ ...props }: React.ComponentProps) { - return ( - - ) + return ; } function DropdownMenuContent({ @@ -43,19 +34,18 @@ function DropdownMenuContent({ data-slot="dropdown-menu-content" sideOffset={sideOffset} align={align} - className={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-32 rounded-lg p-1 shadow-md ring-1 duration-100 z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto data-[state=closed]:overflow-hidden", className )} + className={cn( + "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-32 rounded-lg p-1 shadow-md ring-1 duration-100 z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto data-[state=closed]:overflow-hidden", + className, + )} {...props} /> - ) + ); } -function DropdownMenuGroup({ - ...props -}: React.ComponentProps) { - return ( - - ) +function DropdownMenuGroup({ ...props }: React.ComponentProps) { + return ; } function DropdownMenuItem({ @@ -64,8 +54,8 @@ function DropdownMenuItem({ variant = "default", ...props }: React.ComponentProps & { - inset?: boolean - variant?: "default" | "destructive" + inset?: boolean; + variant?: "default" | "destructive"; }) { return ( - ) + ); } function DropdownMenuCheckboxItem({ @@ -92,7 +82,7 @@ function DropdownMenuCheckboxItem({ data-slot="dropdown-menu-checkbox-item" className={cn( "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground min-h-7 gap-2 rounded-md py-1.5 pr-8 pl-2 text-xs [&_svg:not([class*='size-'])]:size-3.5 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", - className + className, )} checked={checked} {...props} @@ -102,24 +92,18 @@ function DropdownMenuCheckboxItem({ data-slot="dropdown-menu-checkbox-item-indicator" > - + {children} - ) + ); } function DropdownMenuRadioGroup({ ...props }: React.ComponentProps) { - return ( - - ) + return ; } function DropdownMenuRadioItem({ @@ -132,7 +116,7 @@ function DropdownMenuRadioItem({ data-slot="dropdown-menu-radio-item" className={cn( "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground min-h-7 gap-2 rounded-md py-1.5 pr-8 pl-2 text-xs [&_svg:not([class*='size-'])]:size-3.5 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", - className + className, )} {...props} > @@ -141,13 +125,12 @@ function DropdownMenuRadioItem({ data-slot="dropdown-menu-radio-item-indicator" > - + {children} - ) + ); } function DropdownMenuLabel({ @@ -155,7 +138,7 @@ function DropdownMenuLabel({ inset, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( - ) + ); } function DropdownMenuSeparator({ @@ -177,26 +160,24 @@ function DropdownMenuSeparator({ className={cn("bg-border/50 -mx-1 my-1 h-px", className)} {...props} /> - ) + ); } -function DropdownMenuShortcut({ - className, - ...props -}: React.ComponentProps<"span">) { +function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) { return ( - ) + ); } -function DropdownMenuSub({ - ...props -}: React.ComponentProps) { - return +function DropdownMenuSub({ ...props }: React.ComponentProps) { + return ; } function DropdownMenuSubTrigger({ @@ -205,7 +186,7 @@ function DropdownMenuSubTrigger({ children, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( {children} - ) + ); } function DropdownMenuSubContent({ @@ -230,10 +211,13 @@ function DropdownMenuSubContent({ return ( - ) + ); } export { @@ -252,4 +236,4 @@ export { DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, -} +}; diff --git a/apps/packages/ui/src/empty.tsx b/apps/packages/ui/src/empty.tsx index a118491403..1df8c0a2cc 100644 --- a/apps/packages/ui/src/empty.tsx +++ b/apps/packages/ui/src/empty.tsx @@ -1,6 +1,6 @@ -import { cva, type VariantProps } from "class-variance-authority" +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "./lib/utils" +import { cn } from "./lib/utils"; function Empty({ className, ...props }: React.ComponentProps<"div">) { return ( @@ -8,24 +8,21 @@ function Empty({ className, ...props }: React.ComponentProps<"div">) { data-slot="empty" className={cn( "gap-4 rounded-xl border-dashed p-6 flex w-full min-w-0 flex-1 flex-col items-center justify-center text-center text-balance", - className + className, )} {...props} /> - ) + ); } function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) { return (
- ) + ); } const emptyMediaVariants = cva( @@ -40,8 +37,8 @@ const emptyMediaVariants = cva( defaultVariants: { variant: "default", }, - } -) + }, +); function EmptyMedia({ className, @@ -55,7 +52,7 @@ function EmptyMedia({ className={cn(emptyMediaVariants({ variant, className }))} {...props} /> - ) + ); } function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) { @@ -65,7 +62,7 @@ function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) { className={cn("text-sm font-medium tracking-tight", className)} {...props} /> - ) + ); } function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) { @@ -74,11 +71,11 @@ function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) { data-slot="empty-description" className={cn( "text-xs/relaxed text-muted-foreground [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4", - className + className, )} {...props} /> - ) + ); } function EmptyContent({ className, ...props }: React.ComponentProps<"div">) { @@ -87,18 +84,11 @@ function EmptyContent({ className, ...props }: React.ComponentProps<"div">) { data-slot="empty-content" className={cn( "gap-2 text-xs/relaxed flex w-full max-w-sm min-w-0 flex-col items-center text-balance", - className + className, )} {...props} /> - ) + ); } -export { - Empty, - EmptyHeader, - EmptyTitle, - EmptyDescription, - EmptyContent, - EmptyMedia, -} +export { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia }; diff --git a/apps/packages/ui/src/field.tsx b/apps/packages/ui/src/field.tsx index c96adb4bf6..3a4ba7ff52 100644 --- a/apps/packages/ui/src/field.tsx +++ b/apps/packages/ui/src/field.tsx @@ -1,20 +1,23 @@ -"use client" +"use client"; -import { useMemo } from "react" -import { cva, type VariantProps } from "class-variance-authority" +import { useMemo } from "react"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "./lib/utils" -import { Label } from "./label" -import { Separator } from "./separator" +import { cn } from "./lib/utils"; +import { Label } from "./label"; +import { Separator } from "./separator"; function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) { return (
[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3 flex flex-col", className)} + className={cn( + "gap-4 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3 flex flex-col", + className, + )} {...props} /> - ) + ); } function FieldLegend({ @@ -26,10 +29,13 @@ function FieldLegend({ - ) + ); } function FieldGroup({ className, ...props }: React.ComponentProps<"div">) { @@ -38,18 +44,17 @@ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) { data-slot="field-group" className={cn( "gap-4 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4 group/field-group @container/field-group flex w-full flex-col", - className + className, )} {...props} /> - ) + ); } const fieldVariants = cva("data-[invalid=true]:text-destructive gap-2 group/field flex w-full", { variants: { orientation: { - vertical: - "flex-col [&>*]:w-full [&>.sr-only]:w-auto", + vertical: "flex-col [&>*]:w-full [&>.sr-only]:w-auto", horizontal: "flex-row items-center [&>[data-slot=field-label]]:flex-auto has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", responsive: @@ -59,7 +64,7 @@ const fieldVariants = cva("data-[invalid=true]:text-destructive gap-2 group/fiel defaultVariants: { orientation: "vertical", }, -}) +}); function Field({ className, @@ -74,37 +79,31 @@ function Field({ className={cn(fieldVariants({ orientation }), className)} {...props} /> - ) + ); } function FieldContent({ className, ...props }: React.ComponentProps<"div">) { return (
- ) + ); } -function FieldLabel({ - className, - ...props -}: React.ComponentProps) { +function FieldLabel({ className, ...props }: React.ComponentProps) { return (
- ) + ); } export { @@ -224,4 +221,4 @@ export { FieldSet, FieldContent, FieldTitle, -} +}; diff --git a/apps/packages/ui/src/hooks/use-mobile.ts b/apps/packages/ui/src/hooks/use-mobile.ts index 2b0fe1dfef..502fd32393 100644 --- a/apps/packages/ui/src/hooks/use-mobile.ts +++ b/apps/packages/ui/src/hooks/use-mobile.ts @@ -1,19 +1,19 @@ -import * as React from "react" +import * as React from "react"; -const MOBILE_BREAKPOINT = 768 +const MOBILE_BREAKPOINT = 768; export function useIsMobile() { - const [isMobile, setIsMobile] = React.useState(undefined) + const [isMobile, setIsMobile] = React.useState(undefined); React.useEffect(() => { - const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) + const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); const onChange = () => { - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) - } - mql.addEventListener("change", onChange) - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) - return () => mql.removeEventListener("change", onChange) - }, []) + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); + }; + mql.addEventListener("change", onChange); + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); + return () => mql.removeEventListener("change", onChange); + }, []); - return !!isMobile + return !!isMobile; } diff --git a/apps/packages/ui/src/hover-card.tsx b/apps/packages/ui/src/hover-card.tsx index 2e85098ba3..16d0ab93d8 100644 --- a/apps/packages/ui/src/hover-card.tsx +++ b/apps/packages/ui/src/hover-card.tsx @@ -1,22 +1,16 @@ -"use client" +"use client"; -import * as React from "react" -import { HoverCard as HoverCardPrimitive } from "radix-ui" +import * as React from "react"; +import { HoverCard as HoverCardPrimitive } from "radix-ui"; -import { cn } from "./lib/utils" +import { cn } from "./lib/utils"; -function HoverCard({ - ...props -}: React.ComponentProps) { - return +function HoverCard({ ...props }: React.ComponentProps) { + return ; } -function HoverCardTrigger({ - ...props -}: React.ComponentProps) { - return ( - - ) +function HoverCardTrigger({ ...props }: React.ComponentProps) { + return ; } function HoverCardContent({ @@ -33,12 +27,12 @@ function HoverCardContent({ sideOffset={sideOffset} className={cn( "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground w-72 rounded-lg p-2.5 text-xs/relaxed shadow-md ring-1 duration-100 z-50 origin-(--radix-hover-card-content-transform-origin) outline-hidden", - className + className, )} {...props} /> - ) + ); } -export { HoverCard, HoverCardTrigger, HoverCardContent } +export { HoverCard, HoverCardTrigger, HoverCardContent }; diff --git a/apps/packages/ui/src/index.ts b/apps/packages/ui/src/index.ts index 53550740dc..e6ab2887d9 100644 --- a/apps/packages/ui/src/index.ts +++ b/apps/packages/ui/src/index.ts @@ -1,53 +1,53 @@ -export * from './accordion'; -export * from './alert-dialog'; -export * from './alert'; -export * from './aspect-ratio'; -export * from './avatar'; -export * from './badge'; -export * from './breadcrumb'; -export * from './button-group'; -export * from './button'; -export * from './calendar'; -export * from './card'; -export * from './carousel'; -export * from './chart'; -export * from './checkbox'; -export * from './collapsible'; -export * from './command'; -export * from './context-menu'; -export * from './dialog'; -export * from './drawer'; -export * from './dropdown-menu'; -export * from './empty'; -export * from './field'; -export * from './hover-card'; -export * from './input-group'; -export * from './input-otp'; -export * from './input'; -export * from './item'; -export * from './kbd'; -export * from './label'; -export * from './menubar'; -export * from './navigation-menu'; -export * from './pagination'; -export * from './pannel-session'; -export * from './popover'; -export * from './progress'; -export * from './radio-group'; -export * from './resizable'; -export * from './scroll-area'; -export * from './select'; -export * from './separator'; -export * from './sheet'; -export * from './sidebar'; -export * from './skeleton'; -export * from './slider'; -export * from './sonner'; -export * from './spinner'; -export * from './switch'; -export * from './table'; -export * from './tabs'; -export * from './textarea'; -export * from './toggle-group'; -export * from './toggle'; -export * from './tooltip'; +export * from "./accordion"; +export * from "./alert-dialog"; +export * from "./alert"; +export * from "./aspect-ratio"; +export * from "./avatar"; +export * from "./badge"; +export * from "./breadcrumb"; +export * from "./button-group"; +export * from "./button"; +export * from "./calendar"; +export * from "./card"; +export * from "./carousel"; +export * from "./chart"; +export * from "./checkbox"; +export * from "./collapsible"; +export * from "./command"; +export * from "./context-menu"; +export * from "./dialog"; +export * from "./drawer"; +export * from "./dropdown-menu"; +export * from "./empty"; +export * from "./field"; +export * from "./hover-card"; +export * from "./input-group"; +export * from "./input-otp"; +export * from "./input"; +export * from "./item"; +export * from "./kbd"; +export * from "./label"; +export * from "./menubar"; +export * from "./navigation-menu"; +export * from "./pagination"; +export * from "./pannel-session"; +export * from "./popover"; +export * from "./progress"; +export * from "./radio-group"; +export * from "./resizable"; +export * from "./scroll-area"; +export * from "./select"; +export * from "./separator"; +export * from "./sheet"; +export * from "./sidebar"; +export * from "./skeleton"; +export * from "./slider"; +export * from "./sonner"; +export * from "./spinner"; +export * from "./switch"; +export * from "./table"; +export * from "./tabs"; +export * from "./textarea"; +export * from "./toggle-group"; +export * from "./toggle"; +export * from "./tooltip"; diff --git a/apps/packages/ui/src/input-group.tsx b/apps/packages/ui/src/input-group.tsx index 926b7fb26f..d6e17f8256 100644 --- a/apps/packages/ui/src/input-group.tsx +++ b/apps/packages/ui/src/input-group.tsx @@ -1,12 +1,12 @@ -"use client" +"use client"; -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "./lib/utils" -import { Button } from "./button" -import { Input } from "./input" -import { Textarea } from "./textarea" +import { cn } from "./lib/utils"; +import { Button } from "./button"; +import { Input } from "./input"; +import { Textarea } from "./textarea"; function InputGroup({ className, ...props }: React.ComponentProps<"div">) { return ( @@ -15,11 +15,11 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) { role="group" className={cn( "border-input bg-input/20 dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/30 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 h-7 rounded-md border transition-colors has-data-[align=block-end]:rounded-md has-data-[align=block-start]:rounded-md has-[[data-slot=input-group-control]:focus-visible]:ring-[2px] has-[[data-slot][aria-invalid=true]]:ring-[2px] has-[textarea]:rounded-md has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 [[data-slot=combobox-content]_&]:focus-within:border-inherit [[data-slot=combobox-content]_&]:focus-within:ring-0 group/input-group relative flex w-full min-w-0 items-center outline-none has-[>textarea]:h-auto", - className + className, )} {...props} /> - ) + ); } const inputGroupAddonVariants = cva( @@ -38,8 +38,8 @@ const inputGroupAddonVariants = cva( defaultVariants: { align: "inline-start", }, - } -) + }, +); function InputGroupAddon({ className, @@ -54,13 +54,13 @@ function InputGroupAddon({ className={cn(inputGroupAddonVariants({ align }), className)} onClick={(e) => { if ((e.target as HTMLElement).closest("button")) { - return + return; } - e.currentTarget.parentElement?.querySelector("input")?.focus() + e.currentTarget.parentElement?.querySelector("input")?.focus(); }} {...props} /> - ) + ); } const inputGroupButtonVariants = cva( @@ -77,8 +77,8 @@ const inputGroupButtonVariants = cva( defaultVariants: { size: "xs", }, - } -) + }, +); function InputGroupButton({ className, @@ -96,7 +96,7 @@ function InputGroupButton({ className={cn(inputGroupButtonVariants({ size }), className)} {...props} /> - ) + ); } function InputGroupText({ className, ...props }: React.ComponentProps<"span">) { @@ -104,37 +104,37 @@ function InputGroupText({ className, ...props }: React.ComponentProps<"span">) { - ) + ); } -function InputGroupInput({ - className, - ...props -}: React.ComponentProps<"input">) { +function InputGroupInput({ className, ...props }: React.ComponentProps<"input">) { return ( - ) + ); } -function InputGroupTextarea({ - className, - ...props -}: React.ComponentProps<"textarea">) { +function InputGroupTextarea({ className, ...props }: React.ComponentProps<"textarea">) { return (