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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/COMPONENT_PATTERNS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const emit = defineEmits<{...}>()
- `CreateTaskModal.vue` — 表单弹窗组件:收集 name / repoUrl / tokenBudget 创建 Agent,Vue `<Transition>` 原生过渡动画
- `SwarmConfirmModal.vue` — 确认弹窗组件:类型化图标 + 双按钮确认/取消,配合 useConfirm composable
- `SwarmToast.vue` — Toast 通知组件:类型化图标 + 进度条 + 自动消失,配合 useToast composable
- `AgentDetail.vue` — 聊天式多轮对话组件:Header + Info + PR 审阅 + 文件变更 + 聊天消息区(input/output/system/error 直接渲染;think/tool_call/mcp/tool_result 为可折叠气泡,默认收起,点击展开查看完整内容)+ `<textarea>` 输入框(Enter 发送 / Shift+Enter 换行,自动增高)。Info 区任务指令从 `logs` 倒序查找最近 `input` 类型条目渲染,不再依赖 `agent.instruction`。日期字段通过 new Date(string).toLocaleTimeString() 显示。滚动行为:通过 `scroll` 事件监听跟踪用户是否在底部 50px 范围内;当新消息到达或内容流式追加时,若用户之前处于底部则即时滚至底部,若用户已主动上滚则保持当前浏览位置。可折叠消息展开/收起后同样会跟进滚动。**输入框草稿缓存**:通过 `useSwarmStore` 的 `draftInputs` 在组件挂载时恢复、卸载时保存、切换 Agent 时自动迁移草稿内容,避免切视图丢失未发送的输入。所有消息气泡均带 `animate-message-enter` 进入动画(fade-in + slide-up)。PR 审阅区「打回」按钮带 tooltip 说明语义——清空审阅状态、切回就绪态等待用户发新指令,**不会自动让 Agent 修改**(避免历史文案「Agent 继续修改」的误导)。Reviewer 行额外支持 `failed` 状态:自动审阅多次失败(kimi 启动失败 / 卡死等)后用 amber AlertCircle 图标 + 「失败 (×N)」标签 + 截断展示 failureReason,鼠标悬停看完整原因;语义跟「已拒绝」不同——审阅没跑通而非内容被拒,需要人工处置
- `AgentDetail.vue` — 聊天式多轮对话组件:Header + Info + PR 审阅 + 文件变更 + 聊天消息区(input/output/think 支持 **Markdown 渲染 + 代码语法高亮**,基于 `marked` + `highlight.js` + `dompurify` XSS 过滤;tool_call/mcp/tool_result 为可折叠气泡保持等宽纯文本,默认收起,点击展开查看完整内容)+ `<textarea>` 输入框(Enter 发送 / Shift+Enter 换行,自动增高)。Info 区任务指令从 `logs` 倒序查找最近 `input` 类型条目渲染,不再依赖 `agent.instruction`。日期字段通过 new Date(string).toLocaleTimeString() 显示。滚动行为:通过 `scroll` 事件监听跟踪用户是否在底部 50px 范围内;当新消息到达或内容流式追加时,若用户之前处于底部则即时滚至底部,若用户已主动上滚则保持当前浏览位置。可折叠消息展开/收起后同样会跟进滚动。**输入框草稿缓存**:通过 `useSwarmStore` 的 `draftInputs` 在组件挂载时恢复、卸载时保存、切换 Agent 时自动迁移草稿内容,避免切视图丢失未发送的输入。所有消息气泡均带 `animate-message-enter` 进入动画(fade-in + slide-up)。PR 审阅区「打回」按钮带 tooltip 说明语义——清空审阅状态、切回就绪态等待用户发新指令,**不会自动让 Agent 修改**(避免历史文案「Agent 继续修改」的误导)。Reviewer 行额外支持 `failed` 状态:自动审阅多次失败(kimi 启动失败 / 卡死等)后用 amber AlertCircle 图标 + 「失败 (×N)」标签 + 截断展示 failureReason,鼠标悬停看完整原因;语义跟「已拒绝」不同——审阅没跑通而非内容被拒,需要人工处置
- `TaskCard.vue` — 卡片组件:Agent 状态 + Token 进度 + 审阅徽章;状态枚举含 `orphan`(已失效,表示本地缓存中存在但引擎 restore 列表中无对应 ID 的 agent);启动/停止/重启/删除按钮均按 `engineReady` prop 禁用,引擎 restore 完成前置灰;删除操作通过 `useConfirm()` 调用自定义确认弹窗
- `AnalyticsPanel.vue` — 数据展示型组件:状态分布、Token 排行、任务列表;列表项通过 `getLastInput(task.logs)` 展示最后一条 input 指令摘要,与 `AgentDetail.vue` 的 Info 区指令展示逻辑一致
- `SettingsPanel.vue` — 纯信息展示型设置面板,使用 lucide 图标 + code 标签展示命令指引
Expand Down
1 change: 1 addition & 0 deletions docs/CONSTRAINTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ typecheck → lint → analyze → test → check-docs → check-test-sync → b
| Store 修改规范 | 状态必须通过 `useSwarmStore` 方法修改 |
| Bug 反复修复 | 同一 bug 反复出现 → 必须先加 Logger 日志定位根因 → 修复后留痕(根因说明)。禁止盲修。 |
| **禁止硬编码绝对路径** | **非 `tests/` 代码禁止包含硬编码绝对路径**(如 `E:/workspace`、`C:\Python312\...`、`C:\nvm4w\...`)。路径应通过配置、环境变量或运行时探测获取。`tests/` 中允许硬编码(测试用例隔离、可预期)。这是可移植性的底线(vllm 经验)。 |
| 依赖引入需同步文档 | `package.json` 新增/删除依赖后,须在 `docs/FRONTEND.md`(前端依赖)或 `docs/ARCHITECTURE.md`(引擎依赖)中同步更新技术栈说明。 |
| Harness 合规 | bug-fix 分支修改 src/ 代码后,必须同步更新 `docs/`、`exec-plans/` 或 `harness/bug-fix.yaml`。文档是单一事实源。 |
| 代码改动验证 | 任何代码变更必须走 build → start → test → lint/analyze 闭环,全部通过才能开 PR。未验证代码禁止合入 main。 |

Expand Down
1 change: 1 addition & 0 deletions docs/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,4 @@
1. **Vue 而不是 React**:reactive() 对高频日志流更友好
2. **先 Web 后桌面**:先验证 UI 交互,再套 Electron/Tauri 壳
3. **Global Composable 而不是 Pinia**:当前复杂度足够,跨窗口时迁移
4. **引入 marked + highlight.js 做 Markdown 渲染**:Agent 回复天然包含 Markdown 格式(代码块、列表、粗体等),纯文本展示可读性差;配合 DOMPurify 过滤 XSS,代码高亮提升代码块可读性
6 changes: 3 additions & 3 deletions docs/FRONTEND.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## 技术栈

Vue 3 + TypeScript + Vite + Tailwind CSS + lucide-vue-next + Tauri v2 + @tauri-apps/plugin-store
Vue 3 + TypeScript + Vite + Tailwind CSS + lucide-vue-next + Tauri v2 + @tauri-apps/plugin-store + marked + dompurify + highlight.js

## 编码规范

Expand All @@ -29,7 +29,7 @@ Vue 3 + TypeScript + Vite + Tailwind CSS + lucide-vue-next + Tauri v2 + @tauri-a
- `components/SwarmConfirmModal.vue` — 确认弹窗组件:支持 danger/warning/info 类型,配合 useConfirm 使用
- `components/SwarmToast.vue` — Toast 通知组件:支持 error/success/info/warning,自动消失
- `App.vue` — 主入口:布局框架 + 视图路由(dashboard/agent-detail/analytics)+ 全局事件处理(如文件 diff 查看)
- `components/AgentDetail.vue` — Agent 详情:`<textarea>` 指令输入(Enter 发送 / Shift+Enter 换行,自动增高)+ 日志流(含 think / tool_call / mcp / tool_result 可折叠气泡,默认收起,点击展开查看完整内容,智能滚动:通过 `scroll` 事件跟踪用户位置,若用户之前在底部 50px 内则即时跟进,已上滚则保持阅读位置)+ PR 审阅 + 文件变更(点击通过 engine 获取 diff)。输入框草稿通过 `useSwarmStore.draftInputs` 做内存级缓存,切视图/切 Agent 时不丢失未发送内容。所有消息气泡带 `animate-message-enter` 进入动画。「打回」按钮 tooltip 说明:只切回就绪态、不自动触发修改。Reviewer 行支持 `failed` 状态展示(amber 配色 + 失败原因)
- `components/AgentDetail.vue` — Agent 详情:`<textarea>` 指令输入(Enter 发送 / Shift+Enter 换行,自动增高)+ 日志流(含 think / tool_call / mcp / tool_result 可折叠气泡,默认收起,点击展开查看完整内容,智能滚动:通过 `scroll` 事件跟踪用户位置,若用户之前在底部 50px 内则即时跟进,已上滚则保持阅读位置)+ PR 审阅 + 文件变更(点击通过 engine 获取 diff)。**聊天消息气泡(input / output / think)支持 Markdown 渲染 + 代码语法高亮**,基于 `marked` + `highlight.js` + `dompurify`(XSS 过滤)。输入框草稿通过 `useSwarmStore.draftInputs` 做内存级缓存,切视图/切 Agent 时不丢失未发送内容。所有消息气泡带 `animate-message-enter` 进入动画。「打回」按钮 tooltip 说明:只切回就绪态、不自动触发修改。Reviewer 行支持 `failed` 状态展示(amber 配色 + 失败原因)
- `composables/useConfirm.ts` — 全局确认弹窗状态管理(命令式 API)
- `composables/useToast.ts` — 全局 Toast 通知状态管理(命令式 API)
- `components/SettingsPanel.vue` — 系统设置(GitHub Token + Kimi CLI 安装指引)
Expand Down Expand Up @@ -108,7 +108,7 @@ PR CI 中额外运行 `check-test-sync`:若 `src/` 新增代码文件,`tests
| Agent Dashboard(最多5个) | ✅ 真实 | 卡片网格,数量限制,点击进入详情;白色简约 UI |
| Agent 详情页 | ✅ 真实 | 指令输入 + 实时日志 + PR 审阅 + 文件变更;白色简约 UI |
| 新建 Agent 弹窗 | ✅ 真实 | 白色简约 UI |
| 实时日志流 | ✅ 真实 | spawn_process + agent-stream 事件推送(支持 text / think / tool_call / mcp / tool_result 分片);智能滚动,通过 `scroll` 事件跟踪用户位置,底部即时跟进,上滚时不打扰;消息气泡带进入动画 |
| 实时日志流 | ✅ 真实 | spawn_process + agent-stream 事件推送(支持 text / think / tool_call / mcp / tool_result 分片);智能滚动,通过 `scroll` 事件跟踪用户位置,底部即时跟进,上滚时不打扰;消息气泡带进入动画;**支持 Markdown 渲染与代码高亮** |
| PR 审阅面板 | ✅ 真实 | 含审阅者列表、进度、门控;白色简约 UI |
| SettingsPanel(Token 配置) | ✅ 真实 | localStorage 持久化;白色简约 UI |
| 监控分析页 | ✅ 真实 | 状态分布、Token 排行、活跃/审阅任务;白色简约 UI |
Expand Down
51 changes: 51 additions & 0 deletions kimi-code-swarm/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions kimi-code-swarm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@eslint/js": "^9.39.4",
"@playwright/test": "^1.59.1",
"@tauri-apps/cli": "^2.11.0",
"@types/dompurify": "^3.0.5",
"@vue/test-utils": "^2.4.10",
"autoprefixer": "^10.5.0",
"eslint": "^9.39.4",
Expand All @@ -44,7 +45,10 @@
"@tauri-apps/api": "^2.11.0",
"@tauri-apps/plugin-store": "^2.4.3",
"@vitejs/plugin-vue": "^6.0.6",
"dompurify": "^3.4.7",
"highlight.js": "^11.11.1",
"lucide-vue-next": "^1.0.0",
"marked": "^18.0.4",
"vue": "^3.5.33",
"zod": "^4.4.3"
}
Expand Down
27 changes: 24 additions & 3 deletions kimi-code-swarm/src/components/AgentDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,31 @@
User, Bot, Loader2, Brain, Wrench, Server,
ChevronDown, ChevronRight
} from 'lucide-vue-next'
import { marked } from 'marked'
import hljs from 'highlight.js'
import DOMPurify from 'dompurify'
import type { AgentTask } from '../types'
import { getLastInput } from '../utils/getLastInput'
import { useSwarmStore } from '../store/useSwarmStore'

// Configure marked with syntax highlighting via custom renderer
const renderer = new marked.Renderer()
renderer.code = ({ text, lang }: { text: string; lang?: string }) => {
const language = lang && hljs.getLanguage(lang) ? lang : undefined
const highlighted = language
? hljs.highlight(text, { language }).value
: hljs.highlightAuto(text).value
return `<pre><code class="hljs language-${lang || 'plaintext'}">${highlighted}</code></pre>`
}
marked.use({ renderer })
marked.setOptions({ breaks: true })

function renderMarkdown(content: string): string {
if (!content) return ''
const html = marked.parse(content, { async: false }) as string
return DOMPurify.sanitize(html)
}

const props = withDefaults(defineProps<{
agent: AgentTask
/** 引擎是否已 restore 完毕;false 时禁用「启动/发送/停止」等向引擎发命令的按钮 */
Expand Down Expand Up @@ -370,7 +391,7 @@
<div v-if="log.type === 'input'" class="flex justify-end animate-message-enter">
<div class="flex items-end gap-2 max-w-[85%] min-w-0">
<div class="bg-swarm-600 text-white rounded-2xl rounded-tr-sm px-4 py-2.5 shadow-sm">
<p class="text-sm whitespace-pre-wrap break-words leading-relaxed">{{ log.content }}</p>
<div class="markdown-content markdown-content-inverted" v-html="renderMarkdown(log.content)" />

Check warning on line 394 in kimi-code-swarm/src/components/AgentDetail.vue

View workflow job for this annotation

GitHub Actions / check

'v-html' directive can lead to XSS attack
<div class="flex items-center justify-end gap-2 mt-1">
<span v-if="log.tokens" class="text-[10px] opacity-60">{{ log.tokens }} tokens</span>
<span class="text-[10px] opacity-60">{{ new Date(log.timestamp).toLocaleTimeString() }}</span>
Expand All @@ -389,7 +410,7 @@
<Bot class="w-3.5 h-3.5 text-blue-600" />
</div>
<div class="bg-white text-gray-800 rounded-2xl rounded-tl-sm px-4 py-2.5 shadow-sm border border-gray-100">
<p class="text-sm whitespace-pre-wrap break-words leading-relaxed">{{ log.content }}</p>
<div class="markdown-content" v-html="renderMarkdown(log.content)" />

Check warning on line 413 in kimi-code-swarm/src/components/AgentDetail.vue

View workflow job for this annotation

GitHub Actions / check

'v-html' directive can lead to XSS attack
<div class="flex items-center gap-2 mt-1">
<span class="text-[10px] text-gray-400">{{ new Date(log.timestamp).toLocaleTimeString() }}</span>
</div>
Expand All @@ -413,7 +434,7 @@
<ChevronDown v-else class="w-3.5 h-3.5 text-amber-600 shrink-0 ml-2" />
</button>
<div v-if="isLogExpanded(log.id)" class="px-4 pb-2.5">
<p class="text-sm whitespace-pre-wrap break-words leading-relaxed">{{ log.content }}</p>
<div class="markdown-content" v-html="renderMarkdown(log.content)" />

Check warning on line 437 in kimi-code-swarm/src/components/AgentDetail.vue

View workflow job for this annotation

GitHub Actions / check

'v-html' directive can lead to XSS attack
<div class="flex items-center gap-2 mt-1">
<span class="text-[10px] text-amber-400">{{ new Date(log.timestamp).toLocaleTimeString() }}</span>
</div>
Expand Down
Loading
Loading