Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
5824500
feat: update autodev icons with new ai-copilot design
phodal Nov 30, 2025
e33d94f
fix(mpp-idea): replace Material Icons with local IdeaComposeIcons
phodal Nov 30, 2025
6f2fa3e
Merge pull request #8 from phodal/fix/idea-compose-icons-no-material-…
phodal Nov 30, 2025
c30107e
fix(editor): wrap document and caret actions in runReadAction
phodal Nov 30, 2025
c01f9dd
refactor(mpp-idea): reuse CodeReviewViewModel from mpp-ui
phodal Nov 30, 2025
dde5b04
feat(mpp-idea): implement Knowledge Agent functionality
phodal Nov 30, 2025
7ff8db9
Merge pull request #9 from phodal/refactor/reuse-code-review-viewmodel
phodal Nov 30, 2025
19bd676
fix(mpp-idea): address PR review comments for Knowledge Agent
phodal Nov 30, 2025
1624e6b
fix(mpp-idea): guard against invalid TOC levels in IdeaKnowledgeContent
phodal Nov 30, 2025
5749d23
Merge pull request #10 from phodal/feat/mpp-idea-knowledge-agent
phodal Nov 30, 2025
5624660
feat(ui): use TextField state for search and input sync
phodal Nov 30, 2025
507a6bd
chore(build): remove SQLDelight exclusion from dependencies
phodal Nov 30, 2025
aa5566f
refactor(mpp-idea): extract IdeaAgentApp components into separate files
phodal Nov 30, 2025
dfe4521
feat(mpp-idea): enhance IdeaToolCallBubble with expand/collapse and copy
phodal Nov 30, 2025
fc681c1
feat(mpp-idea): add shell execution support to IdeaTerminalOutputBubble
phodal Nov 30, 2025
5fb1d1e
refactor(mpp-idea): simplify IdeaTerminalOutputBubble
phodal Nov 30, 2025
0340be0
fix: address PR review comments
phodal Nov 30, 2025
7d546e8
Merge pull request #11 from phodal/refactor/idea-agent-app-components
phodal Nov 30, 2025
0066c0e
feat(mpp-idea): enhance IdeaBottomToolbar with proper icons and slash…
phodal Nov 30, 2025
f2fc9cb
feat(mpp-idea): add ModelSelector and ModelConfigDialog components
phodal Nov 30, 2025
fccb6db
Merge pull request #13 from phodal/feat/idea-bottom-toolbar-icons
phodal Nov 30, 2025
05d6fbd
feat(mpp-idea): add Jewel-themed markdown renderer with Mermaid support
phodal Nov 30, 2025
0b3eb78
feat(mpp-idea): add Jewel-themed sketch renderers for IntelliJ IDEA
phodal Nov 30, 2025
d6bf8e4
Merge branch 'unit-mesh:master' into master
phodal Nov 30, 2025
c2e3c02
feat(document): add ProductFeatureTreeAgent for automatic feature tre…
phodal Nov 30, 2025
6eae8d6
fix: address PR review comments
phodal Nov 30, 2025
5e68e8e
Merge pull request #15 from phodal/feature/product-feature-tree-agent
phodal Nov 30, 2025
77f7b01
feat(mpp-idea): redesign IdeaAgentTabsHeader with modern segmented co…
phodal Nov 30, 2025
18a10c6
fix(mpp-idea): address PR review comments
phodal Nov 30, 2025
b9f92bd
Merge pull request #16 from phodal/feat/fancy-agent-tabs-header
phodal Nov 30, 2025
8f04e39
feat(mpp-idea): redesign DiffViewerPanel with commit info, file list/…
phodal Nov 30, 2025
ce9f550
feat(mpp-idea): enhance SimpleJewelMarkdown to full-featured renderer
phodal Nov 30, 2025
f87cffc
fix(mpp-idea): improve table renderer with adaptive column weights
phodal Nov 30, 2025
35de079
fix(mpp-idea): fix table cell text extraction
phodal Nov 30, 2025
1fd0352
Merge pull request #17 from phodal/feature/idea-code-review-ui-redesign
phodal Nov 30, 2025
85cc24e
feat(mpp-idea): sync IdeaKnowledgeContent UI with mpp-ui DocumentRead…
phodal Dec 1, 2025
bc75566
Merge pull request #18 from phodal/feature/idea-code-review-ui-redesign
phodal Dec 1, 2025
f140086
feat(markdown): add horizontal scroll for wide tables
phodal Dec 1, 2025
bbddbc8
feat(mpp-idea): implement remote agent support for IntelliJ IDEA plugin
phodal Dec 1, 2025
3c16a42
refactor(markdown): extract and test markdown parsing utilities
phodal Dec 1, 2025
2218c97
fix: address PR review comments
phodal Dec 1, 2025
e8d68f6
fix: address additional PR review comments
phodal Dec 1, 2025
e435d1c
feat(mpp-idea): add IdeaDevInBlockRenderer for devin block support
phodal Dec 1, 2025
22757ff
Merge pull request #19 from phodal/feat/mpp-idea-remote-agent
phodal Dec 1, 2025
e69d23e
fix(mpp-idea): address review comments for IdeaDevInBlockRenderer
phodal Dec 1, 2025
0e4bb1a
Merge pull request #20 from phodal/feat/add-idea-devin-block-renderer
phodal Dec 1, 2025
24e71d1
fix(ui): correct yesterday date calculation in sidebar
phodal Dec 1, 2025
05c8640
refactor(mpp-idea): move toolwindow components to components
phodal Dec 1, 2025
0e389d4
refactor(markdown): rename SimpleJewelMarkdown and extract table
phodal Dec 1, 2025
9a65f2d
refactor(mpp-idea): extract CodeReview components into separate files
phodal Dec 1, 2025
d7207ce
fix: remove unused onItemSelectionChanged parameter from IdeaModifica…
phodal Dec 1, 2025
b9a73c8
refactor(markdown): rename SimpleJewelMarkdown to JewelMarkdownRenderer
phodal Dec 1, 2025
909c92f
Merge pull request #21 from phodal/refactor/code-review-components
phodal Dec 1, 2025
fe724aa
refactor: extract shared renderer models and utils to mpp-core
phodal Dec 1, 2025
761c3c9
refactor: extract TimelineItem and MessageRole to shared mpp-core module
phodal Dec 1, 2025
3c1a8a0
refactor: update ComposeRenderer to use shared TimelineItem from mpp-…
phodal Dec 1, 2025
7441c91
fix: resolve Android compilation error by replacing iOS reference wit…
phodal Dec 1, 2025
272614a
fix: address PR review comments for thread-safety and line number tra…
phodal Dec 1, 2025
10ceea3
Merge pull request #22 from phodal/refactor/code-review-components
phodal Dec 1, 2025
2ea1df1
feat(idea): add Jewel-themed ANSI terminal renderer
phodal Dec 1, 2025
92a5b3c
feat(terminal): add completion status to LiveTerminalItem
phodal Dec 1, 2025
db5b2d5
refactor(idea): remove unused IdeaInputSection file
phodal Dec 1, 2025
3821bc8
feat(mpp-idea): reorganize toolbar layout and add IdeaDevInEditorInput
phodal Dec 1, 2025
3faad12
feat(mpp-idea): add DevIn language completion support to IdeaDevInInput
phodal Dec 1, 2025
cd8c588
feat(mpp-idea): add MCP configuration dialog
phodal Dec 1, 2025
107c4d1
feat(mpp-idea): add prompt optimization dialog
phodal Dec 1, 2025
cac9edc
feat(mpp-idea): improve UI aesthetics and remove workspace display
phodal Dec 1, 2025
593d4ca
feat(mpp-idea): add top toolbar with @ trigger and file selection
phodal Dec 1, 2025
a7ff205
refactor(mpp-idea): remove unused editor input class
phodal Dec 1, 2025
eeda946
feat(mpp-idea): add resizable split pane between content and input area
phodal Dec 1, 2025
697d449
fix(mpp-idea): make EditorTextField resize with split pane
phodal Dec 1, 2025
a989c1f
fix(mpp-idea): position model selector popup above to avoid covering …
phodal Dec 1, 2025
7106899
feat(mpp-idea): add DevIn language support and migrate to Gson
phodal Dec 1, 2025
fffab93
feat(mpp-idea): add extension points for devins-lang module
phodal Dec 1, 2025
160e8fa
Merge pull request #23 from phodal/feature/idea-devin-editor-input
phodal Dec 1, 2025
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
Original file line number Diff line number Diff line change
@@ -1,15 +1,262 @@
package cc.unitmesh.agent.tool.impl

import cc.unitmesh.codegraph.model.*
import cc.unitmesh.codegraph.parser.CodeParser
import cc.unitmesh.codegraph.parser.ios.IosCodeParser
import cc.unitmesh.codegraph.parser.Language

/**
* Android implementation of CodeParser factory
* Uses the same JVM-based implementation as regular JVM
* Android implementation of CodeParser factory.
*
* Note: Android cannot access jvmMain code directly, so we provide a simplified
* regex-based implementation similar to iOS. For full TreeSitter functionality,
* consider using server-side parsing.
*/
actual fun createCodeParser(): CodeParser {
// Android uses JVM backend, but IosCodeParser is a fallback
// In practice, we should use JvmCodeParser but it's not accessible from androidMain
// For now, use the simplified iOS implementation
return IosCodeParser()
return AndroidCodeParser()
}

/**
* Simplified CodeParser for Android platform.
* Uses regex-based parsing to extract basic code structure information.
*/
private class AndroidCodeParser : CodeParser {

override suspend fun parseNodes(
sourceCode: String,
filePath: String,
language: Language
): List<CodeNode> {
return when (language) {
Language.JAVA, Language.KOTLIN -> parseOOPNodes(sourceCode, filePath, language)
Language.JAVASCRIPT, Language.TYPESCRIPT -> parseJSNodes(sourceCode, filePath, language)
Language.PYTHON -> parsePythonNodes(sourceCode, filePath, language)
else -> emptyList()
}
}

override suspend fun parseNodesAndRelationships(
sourceCode: String,
filePath: String,
language: Language
): Pair<List<CodeNode>, List<CodeRelationship>> {
val nodes = parseNodes(sourceCode, filePath, language)
val relationships = buildRelationships(nodes)
return Pair(nodes, relationships)
}

override suspend fun parseCodeGraph(
files: Map<String, String>,
language: Language
): CodeGraph {
val allNodes = mutableListOf<CodeNode>()
val allRelationships = mutableListOf<CodeRelationship>()

for ((filePath, sourceCode) in files) {
val (nodes, relationships) = parseNodesAndRelationships(sourceCode, filePath, language)
allNodes.addAll(nodes)
allRelationships.addAll(relationships)
}

return CodeGraph(
nodes = allNodes,
relationships = allRelationships,
metadata = mapOf(
"language" to language.name,
"fileCount" to files.size.toString(),
"platform" to "Android"
)
)
}

override suspend fun parseImports(
sourceCode: String,
filePath: String,
language: Language
): List<ImportInfo> {
return when (language) {
Language.JAVA, Language.KOTLIN -> extractJvmImports(sourceCode, filePath)
Language.PYTHON -> extractPythonImports(sourceCode, filePath)
Language.JAVASCRIPT, Language.TYPESCRIPT -> extractJsImports(sourceCode, filePath)
else -> emptyList()
}
}

private fun extractJvmImports(content: String, filePath: String): List<ImportInfo> {
val importRegex = Regex("""import\s+(static\s+)?([a-zA-Z_][\w.]*[\w*])""")
return importRegex.findAll(content).map { match ->
// Calculate actual line number from match position
val lineNumber = content.substring(0, match.range.first).count { it == '\n' } + 1
ImportInfo(
path = match.groupValues[2].removeSuffix(".*"),
type = ImportType.MODULE,
filePath = filePath,
startLine = lineNumber,
endLine = lineNumber
)
}.toList()
}

private fun extractPythonImports(content: String, filePath: String): List<ImportInfo> {
val imports = mutableListOf<ImportInfo>()

val fromImportRegex = Regex("""from\s+([\w.]+)\s+import""")
fromImportRegex.findAll(content).forEach { match ->
// Calculate actual line number from match position
val lineNumber = content.substring(0, match.range.first).count { it == '\n' } + 1
imports.add(ImportInfo(
path = match.groupValues[1],
type = ImportType.MODULE,
filePath = filePath,
startLine = lineNumber,
endLine = lineNumber
))
}

val importRegex = Regex("""^import\s+([\w.]+)""", RegexOption.MULTILINE)
importRegex.findAll(content).forEach { match ->
// Calculate actual line number from match position
val lineNumber = content.substring(0, match.range.first).count { it == '\n' } + 1
imports.add(ImportInfo(
path = match.groupValues[1],
type = ImportType.MODULE,
filePath = filePath,
startLine = lineNumber,
endLine = lineNumber
))
}

return imports
}

private fun extractJsImports(content: String, filePath: String): List<ImportInfo> {
val imports = mutableListOf<ImportInfo>()

val es6ImportRegex = Regex("""import\s+(?:.+\s+from\s+)?['"]([@\w./-]+)['"]""")
es6ImportRegex.findAll(content).forEach { match ->
// Calculate actual line number from match position
val lineNumber = content.substring(0, match.range.first).count { it == '\n' } + 1
imports.add(ImportInfo(
path = match.groupValues[1],
type = ImportType.MODULE,
filePath = filePath,
startLine = lineNumber,
endLine = lineNumber
))
}

return imports
}

private fun parseOOPNodes(
sourceCode: String,
filePath: String,
language: Language
): List<CodeNode> {
val nodes = mutableListOf<CodeNode>()
val lines = sourceCode.lines()
val packageName = extractPackageName(sourceCode)

val classPattern = Regex("""(class|interface|enum|object)\s+(\w+)""")

for ((index, line) in lines.withIndex()) {
val currentLine = index + 1

classPattern.find(line)?.let { match ->
val type = when (match.groupValues[1]) {
"class", "object" -> CodeElementType.CLASS
"interface" -> CodeElementType.INTERFACE
"enum" -> CodeElementType.ENUM
else -> CodeElementType.CLASS
}
val name = match.groupValues[2]
nodes.add(createCodeNode(name, type, packageName, filePath, currentLine, language))
}
}

return nodes
}

private fun parseJSNodes(
sourceCode: String,
filePath: String,
language: Language
): List<CodeNode> {
val nodes = mutableListOf<CodeNode>()
val lines = sourceCode.lines()

val classPattern = Regex("""class\s+(\w+)""")

for ((index, line) in lines.withIndex()) {
val currentLine = index + 1

classPattern.find(line)?.let { match ->
val name = match.groupValues[1]
nodes.add(createCodeNode(name, CodeElementType.CLASS, "", filePath, currentLine, language))
}
}

return nodes
}

private fun parsePythonNodes(
sourceCode: String,
filePath: String,
language: Language
): List<CodeNode> {
val nodes = mutableListOf<CodeNode>()
val lines = sourceCode.lines()

val classPattern = Regex("""class\s+(\w+)""")

for ((index, line) in lines.withIndex()) {
val currentLine = index + 1

classPattern.find(line)?.let { match ->
val name = match.groupValues[1]
nodes.add(createCodeNode(name, CodeElementType.CLASS, "", filePath, currentLine, language))
}
}

return nodes
}

private fun extractPackageName(sourceCode: String): String {
val packagePattern = Regex("""package\s+([\w.]+)""")
return packagePattern.find(sourceCode)?.groupValues?.get(1) ?: ""
}

private fun createCodeNode(
name: String,
type: CodeElementType,
packageName: String,
filePath: String,
startLine: Int,
language: Language
): CodeNode {
val qualifiedName = if (packageName.isNotEmpty()) "$packageName.$name" else name
// Use deterministic composite ID to avoid collisions
val id = "$filePath:$startLine:$qualifiedName"

return CodeNode(
id = id,
type = type,
name = name,
packageName = packageName,
filePath = filePath,
startLine = startLine,
// Approximate end line: regex parsing cannot determine actual end line,
// so we use a reasonable default. For accurate end lines, use TreeSitter-based parsing.
endLine = startLine + 10,
startColumn = 0,
endColumn = 0,
qualifiedName = qualifiedName,
content = "",
metadata = mapOf("language" to language.name, "platform" to "Android")
)
}

private fun buildRelationships(nodes: List<CodeNode>): List<CodeRelationship> {
// Simplified: no relationships for basic parsing
return emptyList()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,32 @@ import cc.unitmesh.agent.tool.registry.ToolRegistry
import cc.unitmesh.agent.tool.schema.AgentToolFormatter
import cc.unitmesh.agent.tool.shell.DefaultShellExecutor
import cc.unitmesh.agent.tool.shell.ShellExecutor
import cc.unitmesh.devins.compiler.template.TemplateCompiler
import cc.unitmesh.devins.compiler.variable.VariableTable
import cc.unitmesh.devins.document.DocumentParserService
import cc.unitmesh.llm.KoogLLMService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.datetime.Clock

/**
* Document Task - represents a user query about a document
* Document Agent Mode - determines the agent's behavior
*/
enum class DocumentAgentMode {
DOCUMENT_QUERY, // Original document query mode using DocQL
FEATURE_TREE // Product feature tree generation mode
}

/**
* Document Task - represents a user query about a document or feature tree request
*/
data class DocumentTask(
val query: String,
val documentPath: String? = null
val documentPath: String? = null,
val mode: DocumentAgentMode = DocumentAgentMode.DOCUMENT_QUERY,
val language: String = "EN"
)

/**
Expand Down Expand Up @@ -154,11 +167,35 @@ class DocumentAgent(
private fun buildContext(task: DocumentTask): DocumentContext {
return DocumentContext(
query = task.query,
documentPath = task.documentPath
documentPath = task.documentPath,
mode = task.mode,
language = task.language
)
}

private fun buildSystemPrompt(context: DocumentContext): String {
return when (context.mode) {
DocumentAgentMode.FEATURE_TREE -> buildFeatureTreePrompt(context)
DocumentAgentMode.DOCUMENT_QUERY -> buildDocumentQueryPrompt(context)
}
}

private fun buildFeatureTreePrompt(context: DocumentContext): String {
val template = when (context.language.uppercase()) {
"ZH", "CN" -> ProductFeatureTreeTemplate.ZH
else -> ProductFeatureTreeTemplate.EN
}

val variableTable = VariableTable()
variableTable.addVariable("projectPath", cc.unitmesh.devins.compiler.variable.VariableType.STRING, actualFileSystem.getProjectPath() ?: ".")
variableTable.addVariable("timestamp", cc.unitmesh.devins.compiler.variable.VariableType.STRING, Clock.System.now().toString())
variableTable.addVariable("toolList", cc.unitmesh.devins.compiler.variable.VariableType.STRING, AgentToolFormatter.formatToolListForAI(toolRegistry.getAllTools().values.toList()))

val compiler = TemplateCompiler(variableTable)
return compiler.compile(template)
}

private fun buildDocumentQueryPrompt(context: DocumentContext): String {
return """ You are a Code-First Project Research Assistant.
Your job is to answer developer questions based on the source code (should be exist can be run by DocQL) and project documentation.
DocQL Tool supports structured code search using a TreeSitter parser.
Expand Down Expand Up @@ -270,6 +307,8 @@ ${AgentToolFormatter.formatToolListForAI(toolRegistry.getAllTools().values.toLis

data class DocumentContext(
val query: String,
val documentPath: String?
val documentPath: String?,
val mode: DocumentAgentMode = DocumentAgentMode.DOCUMENT_QUERY,
val language: String = "EN"
)
}
Loading
Loading