diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 68e308fe..456a5beb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,7 +5,7 @@ name: Release on: release: - types: [prereleased, released] + types: [ prereleased, released ] jobs: diff --git a/.gitignore b/.gitignore index 8d89a8e4..c2ea8742 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .gradle .idea .qodana -.* build openai.key .run @@ -19,3 +18,5 @@ html-games.iml test-recordings/ *.index.data *.parsed.json +.intellijPlatform +.kotlin/ diff --git a/CHANGELOG.md b/CHANGELOG.md index c5a6650a..475451d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,13 @@ ## [1.5.10] ### Added + - New Git-related actions: ChatWithCommitAction, ChatWithCommitDiffAction, and ChatWithWorkingCopyDiffAction - SimpleCommandAction for executing custom commands - VCS menu integration with AI Coder options in the VCS log context menu ### Changed + - Updated dependencies: skyenet_version to 1.0.80 and jo-penai to 1.1.0 - Removed kotlinx-coroutines-core dependency - Added Git4Idea and GitHub plugins to the intellij block @@ -19,23 +21,30 @@ - Updated plugin.xml to include new actions and dependencies ### Improved + - Enhanced Git integration capabilities - Streamlined build system and dependency management ## [1.4.0] ### Added + - Support for Gemini models - Support for Mistral Large + ### Removed + - Dynamic action support (temporarily) due to performance issues and bugs + ### Improved + - Patching logic - Various fixes - + ## [1.3.0] ### Added + - `DiffChatAction`: A new action for engaging in a chat session to generate and apply code diffs directly within the IDE. - `MultiDiffChatAction`: Allows for collaborative code review and diff generation across multiple files. @@ -468,13 +477,21 @@ from [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template) [Unreleased]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.5.10...HEAD + [1.5.10]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.4.0...v1.5.10 + [1.4.0]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.3.0...v1.4.0 + [1.3.0]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.2.24...v1.3.0 + [1.2.24]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.2.23...v1.2.24 + [1.2.23]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.2.22...v1.2.23 + [1.2.22]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.2.21...v1.2.22 + [1.2.21]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.2.19...v1.2.21 + [1.2.19]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.2.18...v1.2.19 [1.2.18]: https://github.com/SimiaCryptus/intellij-aicoder/compare/v1.2.14...v1.2.18 diff --git a/README.md b/README.md index c7cafb8d..3326f9f3 100644 --- a/README.md +++ b/README.md @@ -10,31 +10,29 @@ Are you a developer looking to supercharge your coding workflow? Look no further game-changing IntelliJ plugin that harnesses the power of cutting-edge Language Model APIs to revolutionize the way you code! - ## 🌟 Key Features * 🔓 **Open Source**: AI Coding Assistant is released under the Apache 2.0 license, allowing for transparency and community contributions. * 🌐 **Independent Web Interface**: Utilizes a web interface that's lightly bound to IDEA, providing flexibility and ease of use. * 🔀 **Multi-Model and Multi-Provider Support**: Seamlessly integrates with various models and providers, giving you the freedom to choose. -* 🎯 **Explicit Calls**: Based on explicit calls rather than autocomplete, providing you with more control over AI interactions. -* 🤖 **Interactive AI Agents**: Focused on interactive AI agents that can assist with complex coding tasks. -* 🔧 **Patching Support**: Emphasizes patching support, allowing LLMs to work on software changes rather than full rewrites. -* 🔍 **Transparency and User Control**: Puts emphasis on transparency and user control over AI interactions. +* 💬 **Interactive Chat**: Multiple chat interfaces for code discussion, analysis, and modifications +* 🔧 **Smart Code Tools**: Intelligent code editing, documentation, and refactoring capabilities +* 📋 **Advanced Paste Features**: Smart and Fast paste options for automatic code conversion +* 🤖 **AI Agents**: Specialized agents for various tasks including shell commands and web development +* 📊 **Project Management**: Comprehensive planning and task management tools +* 🔍 **Knowledge Management**: Tools for document analysis and data extraction * 💸 **No Membership Fees**: While API access is typically paid, AI Coding Assistant charges no base fee. You only pay for what you use, giving you complete control over your expenses. * 🎛️ **Intuitive Toolbar UI**: Easily configure temperature/model settings and monitor your current token count with AI Coding Assistant's sleek, intuitive toolbar UI. -* 🔍 **API Request Management**: 🎛️ Intercept, edit, and log API requests with ease, giving you granular control over your - plugin's behavior. - +* 🔄 **Version Control Integration**: AI-powered tools for analyzing and working with Git commits and diffs ## 🛠️ Configuration * 🔑 **API Keys**: Securely set up your API keys for various providers. * 🌐 **Web UI**: Access a user-friendly web interface for enhanced interaction. -* 📊 **Verbose & API Sub-logs**: Get detailed logs for debugging and monitoring. -* 🔄 **Diff Windows**: Easily compare and review code changes. - +* ⚙️ **Customizable Settings**: Configure the plugin through the IDE's settings panel +* 📊 **Token Usage Monitoring**: Track your API token usage through the status bar widget ## 📥 Installation & Setup @@ -48,43 +46,59 @@ Getting started with AI Coding Assistant is a breeze: AI Coding Assistant offers a suite of powerful actions designed to streamline your coding process: -### 📝 Editor Actions -* 💬 **Code Chat**: Discuss and analyze code directly in your editor. -* ✏️ **Edit Selection**: Make targeted edits to your code with AI assistance. -* 🔄 **Apply Patch**: Seamlessly apply AI-generated code patches. - -### 📁 File and Folder Actions -* 📄 **File Actions**: Perform AI-assisted operations on individual files. -* 📂 **Folder Actions**: Execute AI-powered tasks across entire folders. -* 🕰️ **Git History**: Analyze and work with your project's Git history. -* 🧪 **Test Results**: Get AI insights on your test results. - -### 🔬 Advanced Features -* 🔧 **Patch Files**: Apply complex patches across multiple files. -* 🔄 **Multi-step Patch**: Execute multi-step patching processes. -* 🛠️ **Auto-fix**: Automatically fix common coding issues. -* 🚀 **Do Something**: General-purpose AI-assisted coding tasks. -* 🐚 **Shell Agent**: Interact with your development environment through an AI-powered shell. - -### 📊 Planning and Organization -* 📅 **Task Planning**: Break down complex coding tasks into manageable steps. -* 🗺️ **Pre-plans**: Create and manage coding project plans. -* 💬 **Plan Chat**: Discuss and refine your coding plans with AI assistance. - -### 🧠 AI Actors and Applications -* 🎭 **Actors**: Utilize purpose-specific AI configurations for various coding tasks. -* 🏗️ **Applications**: Leverage collections of actors for complex coding scenarios. -* 🔍 **Actor Types**: Choose from Simple, Parsed, Coding, and Media actors to suit your needs. - -### 📊 Hierarchical Design and Task Management -* 📈 **DAG Organization**: Benefit from a Directed Acyclic Graph structure for efficient task management. -* 🔄 **Feedback Loops**: Enjoy iterative refinement of your coding projects. -* ✅ **Type Systems and Validation**: Ensure code quality with built-in type checking and validation. +### 💬 Chat Features + +* **AI Assistant Chat**: General-purpose coding assistance and discussions +* **Enhanced AI Chat**: Structured responses for complex coding queries +* **Code Chat**: Context-aware code analysis and suggestions +* **Patch Chat**: Interactive code modification discussions + +### ✏️ Editor Tools + +* **Smart Paste**: Intelligent clipboard content conversion +* **Fast Paste**: Quick code conversion using lightweight models +* **Redo Last**: Repeat recent AI operations +* **Custom Edit**: Flexible code modification tools +* **Recent Code Edits**: Access to previous modifications + +### 📝 Documentation Tools + +* **Describe Code**: Automatic comment generation +* **Add Doc Comments**: Comprehensive documentation generation +* **Add Code Comments**: Context-aware code annotation + +### 🔧 Code Enhancement + +* **Rename Variables**: Intelligent variable renaming +* **Replace with Suggestions**: Context-aware code replacement +* **Filter Lines**: Smart code filtering +* **Implement Stub**: Automatic stub implementation + +### 📋 Project Tools + +* **Modify Files**: Batch file modifications +* **Mass Patch**: Documentation-aware code updates +* **Apply Patch**: Smart patch application +* **Generate Related File**: Context-aware file generation +* **Create File from Description**: Natural language file creation + +### 🤖 AI Agents + +* **Task Runner**: Automated task execution +* **Auto-Plan**: Intelligent project planning +* **Shell Agent**: Command-line automation +* **Web Dev**: Web development assistance + +### 📚 Knowledge Management + +* **Extract Document Data**: Multi-format data extraction +* **View Projector**: Vector visualization +* **Save as Query DB**: Optimized data indexing ## 🚀 Advanced Execution Patterns * 🎯 **Simple Directive Execution**: Execute straightforward coding tasks with ease. -* 💬 **Plan-Supplemented Chat Assistant**: Get AI assistance with context-aware planning capabilities. +* 💬 **Multi-Modal Interaction**: Combine chat, editing, and automation tools for complex tasks. * 🔄 **Objective-Based Cyclic Execution**: (Coming Soon) Achieve complex coding goals through iterative AI-driven processes. * ⚡ **Event-Driven Triggers**: (Coming Soon) Set up automated AI responses to specific coding events. diff --git a/build.gradle.kts b/build.gradle.kts index 5fa1c0ed..b7d89484 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,253 +3,245 @@ import org.jetbrains.changelog.markdownToHTML import org.jetbrains.intellij.platform.gradle.TestFrameworkType import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -fun properties(key: String) = providers.gradleProperty(key).get() +fun properties(key: String) = providers.gradleProperty(key).getOrElse("") plugins { - id("java") - kotlin("jvm") version "2.0.20" - id("org.jetbrains.intellij.platform") version "2.1.0" - id("org.jetbrains.changelog") version "2.2.1" - id("org.jetbrains.qodana") version "2024.2.3" - //id("org.jetbrains.kotlinx.kover") version "0.9.0-RC" - id("org.jetbrains.dokka") version "2.0.0-Beta" + id("java") + kotlin("jvm") version "2.0.20" + id("org.jetbrains.intellij.platform") version "2.1.0" + id("org.jetbrains.changelog") version "2.2.1" + id("org.jetbrains.qodana") version "2024.2.3" + //id("org.jetbrains.kotlinx.kover") version "0.9.0-RC" + id("org.jetbrains.dokka") version "2.0.0-Beta" } -group = "com.github.simiacryptus" +group = "com.simiacryptus" version = properties("pluginVersion") repositories { - mavenCentral() - intellijPlatform { - defaultRepositories() - } + mavenCentral() + intellijPlatform { + defaultRepositories() + } } val jetty_version = "11.0.24" val slf4j_version = "2.0.16" -val skyenet_version = "1.2.17" +val skyenet_version = "1.2.22" val remoterobot_version = "0.11.23" val jackson_version = "2.17.2" dependencies { - implementation("software.amazon.awssdk:bedrock:2.25.9") - implementation("software.amazon.awssdk:bedrockruntime:2.25.9") - implementation("software.amazon.awssdk:s3:2.25.9") - implementation("software.amazon.awssdk:kms:2.25.9") - implementation("software.amazon.awssdk:sso:2.25.9") - implementation("software.amazon.awssdk:ssooidc:2.25.9") - - implementation("org.apache.commons:commons-text:1.11.0") - implementation(group = "com.vladsch.flexmark", name = "flexmark", version = "0.64.8") - implementation("com.googlecode.java-diff-utils:diffutils:1.3.0") - implementation(group = "org.apache.httpcomponents.client5", name = "httpclient5", version = "5.2.3") - - implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.1.12") - implementation(group = "com.simiacryptus.skyenet", name = "kotlin", version = skyenet_version) - implementation(group = "com.simiacryptus.skyenet", name = "core", version = skyenet_version) - implementation(group = "com.simiacryptus.skyenet", name = "webui", version = skyenet_version) - - implementation(group = "com.fasterxml.jackson.core", name = "jackson-databind", version = jackson_version) - implementation(group = "com.fasterxml.jackson.core", name = "jackson-annotations", version = jackson_version) - implementation(group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version = jackson_version) - implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version") - - implementation(group = "org.eclipse.jetty", name = "jetty-server", version = jetty_version) - implementation(group = "org.eclipse.jetty", name = "jetty-servlet", version = jetty_version) - implementation(group = "org.eclipse.jetty", name = "jetty-annotations", version = jetty_version) - implementation(group = "org.eclipse.jetty.websocket", name = "websocket-jetty-server", version = jetty_version) - implementation(group = "org.eclipse.jetty.websocket", name = "websocket-jetty-client", version = jetty_version) - implementation(group = "org.eclipse.jetty.websocket", name = "websocket-servlet", version = jetty_version) - - implementation(group = "org.slf4j", name = "slf4j-api", version = slf4j_version) - - testImplementation(platform("org.junit:junit-bom:5.11.2")) - testImplementation("org.junit.jupiter:junit-jupiter-api") - testImplementation("org.junit.jupiter:junit-jupiter-engine") - testImplementation("org.junit.vintage:junit-vintage-engine") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") - - testImplementation(group = "com.intellij.remoterobot", name = "remote-robot", version = remoterobot_version) - testImplementation(group = "com.intellij.remoterobot", name = "remote-fixtures", version = remoterobot_version) - testImplementation( - group = "com.intellij.remoterobot", - name = "robot-server-plugin", - version = remoterobot_version, - ext = "zip" - ) - - // IntelliJ Platform Gradle Plugin Dependencies Extension - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-dependencies-extension.html - intellijPlatform { - create(providers.gradleProperty("platformType"), providers.gradleProperty("platformVersion")) - - // Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins. - bundledPlugins(providers.gradleProperty("platformBundledPlugins").map { it.split(',') }) - - // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file for plugin from JetBrains Marketplace. - plugins(providers.gradleProperty("platformPlugins").map { it.split(',') }) - - instrumentationTools() - pluginVerifier() - zipSigner() - testFramework(TestFrameworkType.Platform) - } + implementation("software.amazon.awssdk:bedrock:2.25.9") + implementation("software.amazon.awssdk:bedrockruntime:2.25.9") + implementation("software.amazon.awssdk:s3:2.25.9") + implementation("software.amazon.awssdk:kms:2.25.9") + implementation("software.amazon.awssdk:sso:2.25.9") + implementation("software.amazon.awssdk:ssooidc:2.25.9") + + implementation("org.apache.commons:commons-text:1.11.0") + implementation(group = "com.vladsch.flexmark", name = "flexmark", version = "0.64.8") + implementation("com.googlecode.java-diff-utils:diffutils:1.3.0") + implementation(group = "org.apache.httpcomponents.client5", name = "httpclient5", version = "5.2.3") + + implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.1.13") + implementation(group = "com.simiacryptus.skyenet", name = "kotlin", version = skyenet_version) + implementation(group = "com.simiacryptus.skyenet", name = "core", version = skyenet_version) + implementation(group = "com.simiacryptus.skyenet", name = "webui", version = skyenet_version) + + implementation(group = "com.fasterxml.jackson.core", name = "jackson-databind", version = jackson_version) + implementation(group = "com.fasterxml.jackson.core", name = "jackson-annotations", version = jackson_version) + implementation(group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version = jackson_version) + implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version") + + implementation(group = "org.eclipse.jetty", name = "jetty-server", version = jetty_version) + implementation(group = "org.eclipse.jetty", name = "jetty-servlet", version = jetty_version) + implementation(group = "org.eclipse.jetty", name = "jetty-annotations", version = jetty_version) + implementation(group = "org.eclipse.jetty.websocket", name = "websocket-jetty-server", version = jetty_version) + implementation(group = "org.eclipse.jetty.websocket", name = "websocket-jetty-client", version = jetty_version) + implementation(group = "org.eclipse.jetty.websocket", name = "websocket-servlet", version = jetty_version) + + implementation(group = "org.slf4j", name = "slf4j-api", version = slf4j_version) + + testImplementation(platform("org.junit:junit-bom:5.11.2")) + testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation("org.junit.jupiter:junit-jupiter-engine") + testImplementation("org.junit.vintage:junit-vintage-engine") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + + testImplementation(group = "com.intellij.remoterobot", name = "remote-robot", version = remoterobot_version) + testImplementation(group = "com.intellij.remoterobot", name = "remote-fixtures", version = remoterobot_version) + testImplementation( + group = "com.intellij.remoterobot", + name = "robot-server-plugin", + version = remoterobot_version, + ext = "zip" + ) + + // IntelliJ Platform Gradle Plugin Dependencies Extension - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-dependencies-extension.html + intellijPlatform { + create(providers.gradleProperty("platformType"), providers.gradleProperty("platformVersion")) + + // Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins. + bundledPlugins(providers.gradleProperty("platformBundledPlugins").map { it.split(',') }) + + // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file for plugin from JetBrains Marketplace. + plugins(providers.gradleProperty("platformPlugins").map { it.split(',') }) + + instrumentationTools() + pluginVerifier() + zipSigner() + testFramework(TestFrameworkType.Platform) + } } kotlin { - jvmToolchain(17) + jvmToolchain(17) } tasks { - withType { - compilerOptions { - jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) - } - } - - jar { - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - exclude("org/jetbrains/**") - } + withType { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + } + } + + jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + exclude( + "org/jetbrains/org/objectweb/asm/util/**", + "org/jetbrains/org/objectweb/asm/tree/analysis/**", + "org/jetbrains/org/objectweb/asm/tree/**", + "org/jetbrains/org/objectweb/asm/commons/**", + "org/jetbrains/concurrency/**", + "org/jetbrains/org/**", + "org/jetbrains/org/objectweb/asm/signature/**", + "org/jetbrains/org/objectweb/asm/**", + "org/jetbrains/org/objectweb/**" + ) + } - test { - useJUnitPlatform() - testLogging { - events("passed", "skipped", "failed") - } - systemProperty("junit.jupiter.execution.parallel.enabled", "true") - systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") - systemProperty("idea.force.use.core.classloader", "true") - systemProperty("junit.jupiter.extensions.autodetection.enabled", "true") - // Include JUnit 3/4 tests - include("**/*Test.class") + test { + useJUnitPlatform() + testLogging { + events("passed", "skipped", "failed") } - withType { - compilerOptions { - jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) - javaParameters.set(true) - } + systemProperty("junit.jupiter.execution.parallel.enabled", "true") + systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") + systemProperty("idea.force.use.core.classloader", "true") + systemProperty("junit.jupiter.extensions.autodetection.enabled", "true") + // Include JUnit 3/4 tests + include("**/*Test.class") + } + withType { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + javaParameters.set(true) } + } - runIde { - maxHeapSize = "8g" - } + runIde { + maxHeapSize = "8g" + } } // Configure IntelliJ Platform Gradle Plugin - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html intellijPlatform { - pluginConfiguration { - version = providers.gradleProperty("pluginVersion") - - // Extract the section from README.md and provide for the plugin's manifest - description = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map { - val start = "" - val end = "" - - with(it.lines()) { - if (!containsAll(listOf(start, end))) { - throw GradleException("Plugin description section not found in README.md:\n$start ... $end") - } - subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML) - } - } + pluginConfiguration { + version = providers.gradleProperty("pluginVersion") - val changelog = project.changelog // local variable for configuration cache compatibility - // Get the latest available change notes from the changelog file - changeNotes = providers.gradleProperty("pluginVersion").map { pluginVersion -> - with(changelog) { - renderItem( - (getOrNull(pluginVersion) ?: getUnreleased()) - .withHeader(false) - .withEmptySections(false), - Changelog.OutputType.HTML, - ) - } - } + // Extract the section from README.md and provide for the plugin's manifest + description = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map { + val start = "" + val end = "" - ideaVersion { - sinceBuild = providers.gradleProperty("pluginSinceBuild") - untilBuild = providers.gradleProperty("pluginUntilBuild") + with(it.lines()) { + if (!containsAll(listOf(start, end))) { + throw GradleException("Plugin description section not found in README.md:\n$start ... $end") } - } - - signing { - certificateChain = providers.environmentVariable("CERTIFICATE_CHAIN") - privateKey = providers.environmentVariable("PRIVATE_KEY") - password = providers.environmentVariable("PRIVATE_KEY_PASSWORD") - } - - publishing { - // Include VCS plugin - token = providers.environmentVariable("PUBLISH_TOKEN") - // The pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3 - // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more: - // https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel - channels = providers.gradleProperty("pluginVersion").map { listOf(it.substringAfter('-', "").substringBefore('.').ifEmpty { "default" }) } - } - pluginVerification { - ides { - recommended() - } - } + subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML) + } + } + + val changelog = project.changelog // local variable for configuration cache compatibility + // Get the latest available change notes from the changelog file + changeNotes = providers.gradleProperty("pluginVersion").map { pluginVersion -> + with(changelog) { + renderItem( + (getOrNull(pluginVersion) ?: getUnreleased()) + .withHeader(false) + .withEmptySections(false), + Changelog.OutputType.HTML, + ) + } + } + + ideaVersion { + sinceBuild = providers.gradleProperty("pluginSinceBuild") + untilBuild = providers.gradleProperty("pluginUntilBuild") + } + } + + signing { + certificateChain = providers.environmentVariable("CERTIFICATE_CHAIN") + privateKey = providers.environmentVariable("PRIVATE_KEY") + password = providers.environmentVariable("PRIVATE_KEY_PASSWORD") + } + + publishing { + // Include VCS plugin + token = providers.environmentVariable("PUBLISH_TOKEN") + // The pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3 + // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more: + // https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel + channels = providers.gradleProperty("pluginVersion").map { listOf(it.substringAfter('-', "").substringBefore('.').ifEmpty { "default" }) } + } + pluginVerification { + ides { + recommended() + } + } } repositories { - mavenCentral() - intellijPlatform { - defaultRepositories() - } + mavenCentral() + intellijPlatform { + defaultRepositories() + } } -// Configure Gradle Changelog Plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin changelog { - groups.empty() - repositoryUrl = providers.gradleProperty("pluginRepositoryUrl") + groups.empty() + repositoryUrl = providers.gradleProperty("pluginRepositoryUrl") } -// Configure Gradle Kover Plugin - read more: https://github.com/Kotlin/kotlinx-kover#configuration -/* -kover { - reports { - total { - xml { - onCheck = true - } - } - } -} -*/ - tasks { - wrapper { - gradleVersion = providers.gradleProperty("gradleVersion").get() - } - - publishPlugin { - dependsOn(patchChangelog) - } + publishPlugin { + dependsOn(patchChangelog) + } } intellijPlatformTesting { - runIde { - register("runIdeForUiTests") { - task { - jvmArgumentProviders += CommandLineArgumentProvider { - listOf( - "-Drobot-server.port=8082", - "-Dide.mac.message.dialogs.as.sheets=false", - "-Djb.privacy.policy.text=", - "-Djb.consents.confirmation.enabled=false", - "-Dorg.gradle.configuration-cache=false" - ) - } - } - - plugins { - robotServerPlugin() - } + runIde { + register("runIdeForUiTests") { + task { + jvmArgumentProviders += CommandLineArgumentProvider { + listOf( + "-Drobot-server.port=8082", + "-Dide.mac.message.dialogs.as.sheets=false", + "-Djb.privacy.policy.text=", + "-Djb.consents.confirmation.enabled=false", + "-Dorg.gradle.configuration-cache=false" + ) } + } + + plugins { + robotServerPlugin() + } } + } } \ No newline at end of file diff --git a/docs/TaskRunnerApp.md b/docs/TaskRunnerApp.md index 0badd4ea..c35bd4da 100644 --- a/docs/TaskRunnerApp.md +++ b/docs/TaskRunnerApp.md @@ -1,4 +1,7 @@ -The provided Kotlin code outlines a complex application designed for task planning and execution, integrating with a chat server and utilizing AI models for task breakdown, documentation generation, new file creation, file patching, and inquiries. The application leverages several components, including an IntelliJ plugin, a web UI, and AI-driven actors for processing user inputs and generating code or documentation. Below is a mermaid.js diagram that visualizes the high-level architecture and flow of this application. +The provided Kotlin code outlines a complex application designed for task planning and execution, integrating with a chat server and utilizing AI models for +task breakdown, documentation generation, new file creation, file patching, and inquiries. The application leverages several components, including an IntelliJ +plugin, a web UI, and AI-driven actors for processing user inputs and generating code or documentation. Below is a mermaid.js diagram that visualizes the +high-level architecture and flow of this application. ```mermaid graph TD @@ -39,10 +42,14 @@ style M fill:#bfb,stroke:#333,stroke-width:2px ### Key Components and Flow: -- **TaskRunner**: Initiates the task planning process, interacts with the `AppServer` for web UI, selects files via `DataStorage`, and opens a browser window for user interaction. +- **TaskRunner**: Initiates the task planning process, interacts with the `AppServer` for web UI, selects files via `DataStorage`, and opens a browser window + for user interaction. - **AppServer & TaskRunnerApp**: Hosts the application server and registers the `TaskRunnerApp` which manages sessions and settings. - **TaskRunnerAgent**: Acts as the central processor for user messages, utilizing an `ActorSystem` to delegate tasks to specific actors based on the task type. -- **ActorSystem & Actors (TaskBreakdown, DocumentationGenerator, etc.)**: Processes user messages to perform specific actions like task breakdown, documentation generation, file creation, patching, and inquiries. -- **Results (TaskBreakdownResult, Documentation, etc.)**: Outputs generated by the actors, which are used for further task planning, code documentation, file creation, or patching. +- **ActorSystem & Actors (TaskBreakdown, DocumentationGenerator, etc.)**: Processes user messages to perform specific actions like task breakdown, documentation + generation, file creation, patching, and inquiries. +- **Results (TaskBreakdownResult, Documentation, etc.)**: Outputs generated by the actors, which are used for further task planning, code documentation, file + creation, or patching. -This diagram and description provide a simplified overview of the application's architecture and logic flow. The actual implementation may involve more detailed interactions and components not fully captured here. \ No newline at end of file +This diagram and description provide a simplified overview of the application's architecture and logic flow. The actual implementation may involve more detailed +interactions and components not fully captured here. \ No newline at end of file diff --git a/docs/actions_best_practices.md b/docs/actions_best_practices.md new file mode 100644 index 00000000..7cc0f57d --- /dev/null +++ b/docs/actions_best_practices.md @@ -0,0 +1,306 @@ +# AI Coder Action Best Practices + +## 1. Choosing the Right Base Class + +Choose the appropriate base class for your action: + +### BaseAction + +Basic usage: + +```kotlin +class SimpleAction : BaseAction( + name = "My Action", + description = "Does something simple" +) { + override fun handle(event: AnActionEvent) { + val project = event.project ?: return + UITools.run(project, "Processing", true) { progress -> + // Action logic here with progress indication + progress.text = "Doing work..." + } + } +} +``` + +### SelectionAction + +* Provides automatic selection handling and language detection +* Example implementations: ApplyPatchAction, CodeFormatterAction + Advanced usage: + +```kotlin +class CodeFormatterAction : SelectionAction() { + // Custom configuration class + data class FormatterConfig( + val style: String, + val indent: Int + ) + + override fun getConfig(project: Project?): FormatterConfig? { + return FormatterConfig( + style = "google", + indent = 4 + ) + } + + override fun processSelection(state: SelectionState, config: FormatterConfig?): String { + // Access selection context + val code = state.selectedText ?: return "" + val lang = state.language ?: return code + val indent = state.indent?.toString() ?: " " + // Process with configuration + return formatCode(code, lang, config?.style, config?.indent ?: 4) + } +} +``` + +### FileContextAction + +* Provides progress indication and cancellation support +* Manages file refresh and editor updates + Complete example: + +```kotlin +class FileProcessorAction : FileContextAction() { + data class ProcessorConfig( + val outputDir: String, + val options: Map + ) + + override fun getConfig(project: Project?, e: AnActionEvent): ProcessorConfig? { + val dir = UITools.chooseDirectory(project, "Select Output Directory") + return dir?.let { ProcessorConfig(it.path, mapOf()) } + } + + override fun processSelection(state: SelectionState, config: ProcessorConfig?, progress: ProgressIndicator): Array { + progress.text = "Processing ${state.selectedFile.name}" + val outputFile = File(config?.outputDir, "processed_${state.selectedFile.name}") + outputFile.parentFile.mkdirs() + // Process file with progress updates + progress.isIndeterminate = false + processFileWithProgress(state.selectedFile, outputFile, progress) + return arrayOf(outputFile) + } +} +``` + +## Core Principles + +### 1. Thread Safety + +Best practices for thread management: + +* Use WriteCommandAction for document modifications +* Avoid blocking EDT (Event Dispatch Thread) +* Handle background tasks properly + +```kotlin +// Good example * proper thread handling: +WriteCommandAction.runWriteCommandAction(project) { + try { + UITools.run(project, "Processing", true) { progress -> + progress.isIndeterminate = false + progress.text = "Processing..." + ApplicationManager.getApplication().executeOnPooledThread { + // Long running operation + progress.fraction = 0.5 + } + } + } catch (e: Throwable) { + UITools.error(log, "Error", e) + } +} + +// Bad example * avoid: +Thread { + document.setText("new text") // Don't modify documents outside WriteCommandAction +}.start() +``` + +### 2. Error Handling + +Comprehensive error handling strategy: + +* Use structured error handling +* Provide user feedback +* Log errors appropriately + +```kotlin +// Good example: +try { + processFile(file) +} catch (e: IOException) { + log.error("Failed to process file: ${file.path}", e) + val choice = UITools.showErrorDialog( + project, + "Failed to process file: ${e.message}\nWould you like to retry?", + "Error", + arrayOf("Retry", "Cancel") + ) + if (choice == 0) { + // Retry logic + processFile(file) + } +} finally { + cleanup() +} +``` + +### 3. Progress Indication + +Guidelines for progress feedback: + +* Update progress frequently +* Include operation details in progress text + +```kotlin +UITools.run(project, "Processing Files", true) { progress -> + progress.text = "Initializing..." + files.forEachIndexed { index, file -> + if (progress.isCanceled) throw InterruptedException() + progress.fraction = index.toDouble() / files.size + progress.text = "Processing ${file.name} (${index + 1}/${files.size})" + processFile(file) + } +} +``` + +### 4. Configuration + +* Use `getConfig()` to get user input/settings +* Validate configurations before proceeding +* Store recent configurations where appropriate +* Use `AppSettingsState` for persistent settings + +```kotlin +override fun getConfig(project: Project?, e: AnActionEvent): Settings { + return Settings( + UITools.showDialog( + project, + SettingsUI::class.java, + UserSettings::class.java, + "Dialog Title" + ), + project + ) +} +``` + +### 5. Action Enablement + +* Implement `isEnabled()` to control when action is available +* Check for null safety +* Verify required context (files, selection, etc) +* Consider language support requirements + +```kotlin +override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val file = UITools.getSelectedFile(event) ?: return false + return isLanguageSupported(getComputerLanguage(event)) +} +``` + +### 6. UI Integration + +* Use IntelliJ UI components and dialogs +* Follow IntelliJ UI guidelines +* Provide appropriate feedback to users +* Support undo/redo operations + +### 7. AI Integration + +* Use appropriate models for the task +* Handle API errors gracefully +* Provide meaningful prompts +* Process AI responses appropriately + +```kotlin +val response = ChatProxy( + clazz = API::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature +).create() +``` + +### 8. Code Organization + +* Keep actions focused on a single responsibility +* Extract common functionality to utility classes +* Use appropriate inheritance hierarchy +* Follow Kotlin coding conventions + +### 9. Documentation + +* Document action purpose and usage +* Include example usage where helpful +* Document configuration options +* Explain any special requirements + +### 10. Testing + +* Test action enablement logic +* Test configuration validation +* Test error handling +* Test with different file types/languages + +## Common Patterns + +### Chat Actions + +* Use `SessionProxyServer` for chat interfaces +* Configure appropriate chat models +* Handle chat session lifecycle +* Support conversation context + +### File Operations + +* Use `FileContextAction` base class +* Handle file system operations safely +* Support undo/redo +* Refresh file system after changes + +### Code Modifications + +* Use `SelectionAction` for code changes +* Support appropriate languages +* Handle code formatting +* Preserve indentation + +## Specific Guidelines + +### For AI Code Generation + +1. Use appropriate temperature settings +2. Validate generated code +3. Format code appropriately +4. Handle partial generations + +### For File Operations + +1. Check file existence +2. Handle file permissions +3. Support large files +4. Refresh file system + +### For UI Integration + +1. Use progress indicators +2. Show meaningful messages +3. Support cancellation +4. Follow IntelliJ guidelines + +## Best Practices Checklist + +* [ ] Extends appropriate base class +* [ ] Implements proper error handling +* [ ] Shows progress for long operations +* [ ] Validates configurations +* [ ] Implements proper enablement logic +* [ ] Follows UI guidelines +* [ ] Handles AI integration properly +* [ ] Includes proper documentation +* [ ] Supports undo/redo +* [ ] Includes appropriate tests \ No newline at end of file diff --git a/docs/code_review.prompt.md b/docs/code_review.prompt.md index e88f292b..697156a3 100644 --- a/docs/code_review.prompt.md +++ b/docs/code_review.prompt.md @@ -21,7 +21,7 @@ - 🚀 **Performance:** Suggestions to improve the code's efficiency. - 🔒 **Security:** Concerns related to vulnerabilities or insecure code practices. - 📚 **Documentation:** Recommendations to improve or add comments and documentation for better clarity. - + ## Sections ### 1. Overview @@ -37,16 +37,18 @@ [List specific issues, bugs, or areas for improvement. Use the severity levels and note types from the Review Key.] 1. [😊/😐/😠][💡/🐛/🧹/🚀/🔒/📚] [Issue Title] - - Description: [Detailed explanation of the issue] - - Recommendation: [Suggested solution or improvement] - - Rationale: [Reasoning behind the recommendation] - - Risks: [Description of potential risks or challenges] + +- Description: [Detailed explanation of the issue] +- Recommendation: [Suggested solution or improvement] +- Rationale: [Reasoning behind the recommendation] +- Risks: [Description of potential risks or challenges] 2. [😊/😐/😠][💡/🐛/🧹/🚀/🔒/📚] [Issue Title] - - Description: [Detailed explanation of the issue] - - Recommendation: [Suggested solution or improvement] - - Rationale: [Reasoning behind the recommendation] - - Risks: [Description of potential risks or challenges] + +- Description: [Detailed explanation of the issue] +- Recommendation: [Suggested solution or improvement] +- Rationale: [Reasoning behind the recommendation] +- Risks: [Description of potential risks or challenges] [Add more issues as needed] diff --git a/docs/coding_standards.md b/docs/coding_standards.md index 08fa6d8c..6e55167a 100644 --- a/docs/coding_standards.md +++ b/docs/coding_standards.md @@ -15,7 +15,7 @@ to ensure consistency, readability, and maintainability of the codebase. - **Classes and Interfaces**: Use PascalCase and be descriptive. Example: `StaticAppSettingsConfigurable`. - **Functions and Variables**: Use camelCase and be descriptive. Example: `buildComponent`. - **Constants**: Use UPPER_SNAKE_CASE. Example: `API_PROVIDER`. -- **Packages**: Use lowercase and avoid underscores. Example: `com.github.simiacryptus.aicoder.util`. +- **Packages**: Use lowercase and avoid underscores. Example: `com.simiacryptus.aicoder.util`. ## Formatting diff --git a/docs/demotest_narration.md b/docs/demotest_narration.md index 24e6bbad..f291e8bf 100644 --- a/docs/demotest_narration.md +++ b/docs/demotest_narration.md @@ -4,30 +4,36 @@ Here's a document with guidance and best practices for the narration of demotest ## 1. Introduction -Narrating demotests is crucial for creating engaging and informative demonstrations of software features. This document provides guidelines and best practices to ensure consistent, clear, and effective narration across all demotests. +Narrating demotests is crucial for creating engaging and informative demonstrations of software features. This document provides guidelines and best practices +to ensure consistent, clear, and effective narration across all demotests. ## 2. General Principles ### 2.1 Clarity + - Use simple, concise language - Avoid technical jargon unless necessary - Explain acronyms and technical terms when first used ### 2.2 Consistency + - Maintain a consistent tone and style across all demotests - Use standardized phrases for common actions ### 2.3 Engagement + - Use an enthusiastic and positive tone - Frame the demo as a journey of discovery ### 2.4 Pacing + - Speak at a moderate pace - Pause briefly between major steps ## 3. Structure of Narration ### 3.1 Introduction + - Welcome the audience - Briefly state the feature being demonstrated - Set expectations for what will be shown @@ -36,6 +42,7 @@ Example: "Welcome to the AI Coder demo. We'll demonstrate the Code Chat feature." ### 3.2 Step-by-Step Narration + - Announce each major step before performing it - Explain the purpose of each action - Describe what's happening on the screen @@ -44,6 +51,7 @@ Example: "Now, we'll open a Kotlin file to start a code chat." ### 3.3 Highlighting Key Points + - Emphasize important features or benefits - Explain the significance of certain actions or results @@ -51,6 +59,7 @@ Example: "Notice how quickly the AI generated a response. This can significantly speed up your workflow." ### 3.4 Handling Delays + - Acknowledge when waiting for processes to complete - Use this time to provide additional context or benefits @@ -58,6 +67,7 @@ Example: "While we're waiting for the AI to generate a response, let me explain how this feature can improve code quality." ### 3.5 Conclusion + - Summarize what was demonstrated - Reinforce the key benefits - Thank the audience @@ -68,21 +78,27 @@ Example: ## 4. Best Practices ### 4.1 Use Active Voice + Prefer "We'll select the AI Coder option" over "The AI Coder option will be selected." ### 4.2 Be Descriptive + Describe visual elements and actions for those who might not be able to see the screen. ### 4.3 Anticipate Questions + Try to address potential questions in your narration before they arise. ### 4.4 Handle Errors Gracefully + If something unexpected occurs, acknowledge it calmly and explain how you're addressing it. ### 4.5 Maintain Professionalism + Avoid using slang or informal language. Maintain a professional yet friendly tone. ### 4.6 Practice Inclusive Language + Use gender-neutral terms and avoid assumptions about the audience's technical knowledge. ## 5. Specific Phrases for Common Actions @@ -95,4 +111,5 @@ Use gender-neutral terms and avoid assumptions about the audience's technical kn ## 6. Conclusion -Effective narration can greatly enhance the impact of demotests. By following these guidelines and best practices, you can create engaging, informative, and professional demonstrations that effectively showcase the features of the AI Coder plugin. \ No newline at end of file +Effective narration can greatly enhance the impact of demotests. By following these guidelines and best practices, you can create engaging, informative, and +professional demonstrations that effectively showcase the features of the AI Coder plugin. \ No newline at end of file diff --git a/docs/feature_roadmap.md b/docs/feature_roadmap.md index 02ab4dea..527b92ad 100644 --- a/docs/feature_roadmap.md +++ b/docs/feature_roadmap.md @@ -1,156 +1,191 @@ # java\com\github\simiacryptus\aicoder\util\TextBlock.java -Developing a feature roadmap for the `TextBlock` interface and its implementation involves planning out enhancements, optimizations, and new functionalities that can be added over time to make it more robust, user-friendly, and versatile. Below is a proposed development roadmap that outlines potential phases and features to be developed: - +Developing a feature roadmap for the `TextBlock` interface and its implementation involves planning out enhancements, optimizations, and new functionalities +that can be added over time to make it more robust, user-friendly, and versatile. Below is a proposed development roadmap that outlines potential phases and +features to be developed: #### Phase 1: Core Functionality Enhancement + - **Customizable Delimiters**: Allow users to specify custom delimiters instead of being restricted to `\n` for new lines. - **Trimming Options**: Implement methods to trim whitespace from the beginning and end of the text block, as well as an option to trim each line individually. - **Empty Line Removal**: Add functionality to remove empty lines from the text block, with an option to keep a single empty line as a separator if needed. - #### Phase 2: Formatting and Styling + - **Automatic Indentation**: Develop methods to automatically indent new lines based on the structure of the text, such as for code or JSON formatting. -- **Line Wrapping**: Introduce line wrapping capabilities, where long lines can be wrapped according to a specified width, with support for indenting wrapped lines. +- **Line Wrapping**: Introduce line wrapping capabilities, where long lines can be wrapped according to a specified width, with support for indenting wrapped + lines. - **Styling Hooks**: Create hooks or callbacks that allow for the styling of text (e.g., bold, italic) based on patterns or conditions. - #### Phase 3: Interoperability and Extensions + - **Markdown Support**: Implement support for parsing and generating Markdown-formatted text blocks, including headers, lists, and code blocks. - **HTML Conversion**: Develop functionality to convert the text block into HTML format, preserving indentation and line breaks, and optionally styling. - **File I/O Integration**: Add methods for reading from and writing to files directly, simplifying the process of working with text files. - #### Phase 4: Performance Optimization + - **Lazy Evaluation**: Optimize the internal handling of text blocks to use lazy evaluation where possible, reducing memory usage and improving performance. - **Caching Mechanisms**: Implement caching for frequently accessed or computed properties of the text block, such as its length or hash code. - **Parallel Processing**: Explore opportunities for parallel processing, particularly in methods that involve transforming or analyzing the text block content. - #### Phase 5: Advanced Features -- **Diff and Merge**: Introduce functionality to compute the diff between two text blocks and to merge changes, useful for version control systems. -- **Search and Replace**: Enhance the search capabilities to include regular expressions, and implement a versatile replace function that supports callbacks for dynamic replacement. -- **Annotations and Comments**: Allow for the embedding of annotations or comments within the text block that can be optionally included or excluded from the output. +- **Diff and Merge**: Introduce functionality to compute the diff between two text blocks and to merge changes, useful for version control systems. +- **Search and Replace**: Enhance the search capabilities to include regular expressions, and implement a versatile replace function that supports callbacks for + dynamic replacement. +- **Annotations and Comments**: Allow for the embedding of annotations or comments within the text block that can be optionally included or excluded from the + output. #### Phase 6: User Experience and Documentation + - **Interactive Documentation**: Develop interactive online documentation that allows users to try out methods and see the results in real-time. -- **Tutorials and Examples**: Create a comprehensive set of tutorials and example projects demonstrating the use of the `TextBlock` interface in various scenarios. +- **Tutorials and Examples**: Create a comprehensive set of tutorials and example projects demonstrating the use of the `TextBlock` interface in various + scenarios. - **Community Feedback Loop**: Establish a system for gathering user feedback and requests to inform future development priorities. -This roadmap is designed to be iterative, with each phase building upon the previous ones. It's important to regularly review and adjust the roadmap based on user feedback, technological advancements, and changing requirements. +This roadmap is designed to be iterative, with each phase building upon the previous ones. It's important to regularly review and adjust the roadmap based on +user feedback, technological advancements, and changing requirements. # java\com\github\simiacryptus\aicoder\util\IndentedText.java -Developing a feature roadmap for the `IndentedText` class involves planning enhancements and new functionalities that can make the class more versatile and useful in various applications. Here's a proposed development roadmap: - +Developing a feature roadmap for the `IndentedText` class involves planning enhancements and new functionalities that can make the class more versatile and +useful in various applications. Here's a proposed development roadmap: #### Phase 1: Core Functionality Enhancements -- **1.1 Customizable Tab Replacement:** Allow users to specify their own tab replacement string instead of the fixed two spaces. This would involve modifying the `fromString` method to accept an additional parameter for the tab replacement. -- **1.2 Trim Empty Lines:** Implement functionality to automatically trim leading and trailing empty lines from the text block upon creation or conversion from a string. This can help in maintaining cleaner text blocks. -- **1.3 Line Manipulation Methods:** Add methods to insert, delete, and replace specific lines within the text block. This would greatly enhance the manipulative capabilities of the class. +- **1.1 Customizable Tab Replacement:** Allow users to specify their own tab replacement string instead of the fixed two spaces. This would involve modifying + the `fromString` method to accept an additional parameter for the tab replacement. +- **1.2 Trim Empty Lines:** Implement functionality to automatically trim leading and trailing empty lines from the text block upon creation or conversion from + a string. This can help in maintaining cleaner text blocks. +- **1.3 Line Manipulation Methods:** Add methods to insert, delete, and replace specific lines within the text block. This would greatly enhance the + manipulative capabilities of the class. #### Phase 2: Advanced Formatting Features -- **2.1 Auto-Indentation Adjustment:** Develop a method to automatically adjust the indentation based on a specified pattern or a programming language syntax. This could be particularly useful for code formatting. + +- **2.1 Auto-Indentation Adjustment:** Develop a method to automatically adjust the indentation based on a specified pattern or a programming language syntax. + This could be particularly useful for code formatting. - **2.2 Comment Handling:** Introduce methods to comment or uncomment lines or blocks of text according to the syntax of a specified programming language. - **2.3 Block Merging:** Implement a feature to merge two or more `IndentedText` objects, intelligently adjusting their indentations to maintain readability. - #### Phase 3: Integration and Usability Improvements -- **3.1 IDE Plugin:** Start the development of plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA and Visual Studio Code to directly manipulate `IndentedText` objects within the editor. -- **3.2 Command-Line Tool:** Create a command-line tool for quick conversions and manipulations of text files using the `IndentedText` functionalities. This tool could support batch processing of files. -- **3.3 Performance Optimization:** Conduct a thorough performance analysis and optimization, especially focusing on memory usage and processing speed for large text blocks. +- **3.1 IDE Plugin:** Start the development of plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA and Visual Studio Code to + directly manipulate `IndentedText` objects within the editor. +- **3.2 Command-Line Tool:** Create a command-line tool for quick conversions and manipulations of text files using the `IndentedText` functionalities. This + tool could support batch processing of files. +- **3.3 Performance Optimization:** Conduct a thorough performance analysis and optimization, especially focusing on memory usage and processing speed for large + text blocks. #### Phase 4: Collaboration and Sharing -- **4.1 Version Control Integration:** Develop features to better integrate with version control systems like Git, facilitating the tracking of changes in `IndentedText` objects over time. -- **4.2 Cloud Storage Support:** Implement support for storing and retrieving `IndentedText` objects from cloud storage services like AWS S3, Google Cloud Storage, or Microsoft Azure Blob Storage. -- **4.3 Collaboration Features:** Add functionalities to allow multiple users to work on the same `IndentedText` object simultaneously, similar to Google Docs. This would involve conflict resolution and change tracking mechanisms. +- **4.1 Version Control Integration:** Develop features to better integrate with version control systems like Git, facilitating the tracking of changes in + `IndentedText` objects over time. +- **4.2 Cloud Storage Support:** Implement support for storing and retrieving `IndentedText` objects from cloud storage services like AWS S3, Google Cloud + Storage, or Microsoft Azure Blob Storage. +- **4.3 Collaboration Features:** Add functionalities to allow multiple users to work on the same `IndentedText` object simultaneously, similar to Google Docs. + This would involve conflict resolution and change tracking mechanisms. #### Phase 5: Extensibility and Customization -- **5.1 Plugin Architecture:** Design and implement a plugin architecture that allows third-party developers to extend the functionality of the `IndentedText` class with custom features, such as new formatting rules, language-specific enhancements, or integration with other tools and services. -- **5.2 User-Defined Macros:** Allow users to define their own macros or scripts that can be applied to `IndentedText` objects for custom manipulations and transformations. -This roadmap outlines a comprehensive plan to evolve the `IndentedText` class into a more powerful and flexible tool for handling and manipulating indented text blocks. Each phase builds upon the previous ones, gradually increasing the class's capabilities and applications. +- **5.1 Plugin Architecture:** Design and implement a plugin architecture that allows third-party developers to extend the functionality of the `IndentedText` + class with custom features, such as new formatting rules, language-specific enhancements, or integration with other tools and services. +- **5.2 User-Defined Macros:** Allow users to define their own macros or scripts that can be applied to `IndentedText` objects for custom manipulations and + transformations. -# kotlin\com\github\simiacryptus\aicoder\actions\BaseAction.kt +This roadmap outlines a comprehensive plan to evolve the `IndentedText` class into a more powerful and flexible tool for handling and manipulating indented text +blocks. Each phase builds upon the previous ones, gradually increasing the class's capabilities and applications. -The code provided outlines a base action class for an IntelliJ IDEA plugin, designed to integrate with OpenAI's API. This class serves as a foundation for creating actions within the IDE, handling user interactions, and managing API calls. To further develop this plugin and enhance its capabilities, a feature development roadmap is proposed. This roadmap aims to expand the plugin's functionality, improve user experience, and ensure robustness and scalability. +# kotlin\com\github\simiacryptus\aicoder\actions\BaseAction.kt +The code provided outlines a base action class for an IntelliJ IDEA plugin, designed to integrate with OpenAI's API. This class serves as a foundation for +creating actions within the IDE, handling user interactions, and managing API calls. To further develop this plugin and enhance its capabilities, a feature +development roadmap is proposed. This roadmap aims to expand the plugin's functionality, improve user experience, and ensure robustness and scalability. #### Phase 1: Core Functionality Enhancement -- **Custom Action Creation**: Develop a framework for easily creating custom actions that interact with OpenAI's API, allowing users to perform a wide range of tasks directly from the IDE. -- **API Interaction Improvement**: Enhance the API interaction mechanism to support more OpenAI features, such as fine-tuning, model selection, and advanced configurations. -- **Error Handling and Logging**: Improve error handling and logging mechanisms to provide clearer feedback to users and facilitate easier debugging. +- **Custom Action Creation**: Develop a framework for easily creating custom actions that interact with OpenAI's API, allowing users to perform a wide range of + tasks directly from the IDE. +- **API Interaction Improvement**: Enhance the API interaction mechanism to support more OpenAI features, such as fine-tuning, model selection, and advanced + configurations. +- **Error Handling and Logging**: Improve error handling and logging mechanisms to provide clearer feedback to users and facilitate easier debugging. #### Phase 2: User Interface and Experience -- **Configuration UI**: Implement a user interface for configuring the plugin settings, including API keys, default models, and other preferences. -- **Action Feedback**: Develop a system for providing immediate and informative feedback to users after performing actions, including success messages, error notifications, and AI-generated suggestions. -- **Documentation and Help**: Create comprehensive documentation and in-plugin help guides to assist users in understanding how to use the plugin and its features effectively. +- **Configuration UI**: Implement a user interface for configuring the plugin settings, including API keys, default models, and other preferences. +- **Action Feedback**: Develop a system for providing immediate and informative feedback to users after performing actions, including success messages, error + notifications, and AI-generated suggestions. +- **Documentation and Help**: Create comprehensive documentation and in-plugin help guides to assist users in understanding how to use the plugin and its + features effectively. #### Phase 3: Performance and Scalability -- **Asynchronous Processing**: Enhance the plugin to perform API calls and other intensive tasks asynchronously, improving the responsiveness of the IDE. -- **Resource Management**: Implement mechanisms for managing and optimizing the use of resources, such as memory and network bandwidth, especially during heavy API interactions. -- **Scalability Enhancements**: Ensure that the plugin can scale to support a large number of actions and users, including considerations for concurrent actions and data caching. +- **Asynchronous Processing**: Enhance the plugin to perform API calls and other intensive tasks asynchronously, improving the responsiveness of the IDE. +- **Resource Management**: Implement mechanisms for managing and optimizing the use of resources, such as memory and network bandwidth, especially during heavy + API interactions. +- **Scalability Enhancements**: Ensure that the plugin can scale to support a large number of actions and users, including considerations for concurrent actions + and data caching. #### Phase 4: Advanced Features and Integration -- **Code Generation and Refactoring**: Integrate advanced code generation and refactoring features using OpenAI's capabilities, allowing users to generate code snippets, refactor existing code, and receive coding suggestions. -- **Collaborative Features**: Explore the addition of collaborative features, enabling teams to share actions, configurations, and AI-generated content within the IDE. -- **Extended IDE Support**: Expand the plugin to support additional IDEs beyond IntelliJ IDEA, such as Eclipse and Visual Studio Code, broadening the user base. +- **Code Generation and Refactoring**: Integrate advanced code generation and refactoring features using OpenAI's capabilities, allowing users to generate code + snippets, refactor existing code, and receive coding suggestions. +- **Collaborative Features**: Explore the addition of collaborative features, enabling teams to share actions, configurations, and AI-generated content within + the IDE. +- **Extended IDE Support**: Expand the plugin to support additional IDEs beyond IntelliJ IDEA, such as Eclipse and Visual Studio Code, broadening the user base. #### Phase 5: Security and Compliance -- **Security Enhancements**: Implement robust security measures to protect user data, API keys, and generated content, including encryption and secure storage options. -- **Compliance and Privacy**: Ensure that the plugin complies with relevant data protection and privacy regulations, providing users with control over their data and transparency about its use. +- **Security Enhancements**: Implement robust security measures to protect user data, API keys, and generated content, including encryption and secure storage + options. +- **Compliance and Privacy**: Ensure that the plugin complies with relevant data protection and privacy regulations, providing users with control over their + data and transparency about its use. #### Phase 6: Community and Open Source Development -- **Open Source Contributions**: Open source the plugin and encourage community contributions, allowing developers to add new features, fix bugs, and improve the plugin. -- **Plugin Marketplace**: Explore the possibility of listing the plugin on JetBrains Marketplace and other platforms, making it easily accessible to a wider audience. -- **Community Engagement**: Foster a community around the plugin, including forums, documentation, and support channels, to gather feedback, share use cases, and collaborate on development. -This roadmap outlines a comprehensive plan for developing the IntelliJ IDEA plugin, focusing on enhancing functionality, user experience, and scalability, while also considering security, compliance, and community engagement. +- **Open Source Contributions**: Open source the plugin and encourage community contributions, allowing developers to add new features, fix bugs, and improve + the plugin. +- **Plugin Marketplace**: Explore the possibility of listing the plugin on JetBrains Marketplace and other platforms, making it easily accessible to a wider + audience. +- **Community Engagement**: Foster a community around the plugin, including forums, documentation, and support channels, to gather feedback, share use cases, + and collaborate on development. -# .gitignore +This roadmap outlines a comprehensive plan for developing the IntelliJ IDEA plugin, focusing on enhancing functionality, user experience, and scalability, while +also considering security, compliance, and community engagement. -Creating a feature development roadmap involves planning and organizing the development of new features for a product over time. It helps teams prioritize features, allocate resources efficiently, and communicate the development timeline to stakeholders. Below is a step-by-step guide to creating a feature development roadmap, along with a simple code example to illustrate how you might track and manage this roadmap using a basic Python script. +# .gitignore +Creating a feature development roadmap involves planning and organizing the development of new features for a product over time. It helps teams prioritize +features, allocate resources efficiently, and communicate the development timeline to stakeholders. Below is a step-by-step guide to creating a feature +development roadmap, along with a simple code example to illustrate how you might track and manage this roadmap using a basic Python script. #### Step 1: Identify Key Features and Objectives -Start by listing all the features you want to develop. For each feature, define its objective, how it aligns with your product goals, and its expected impact on your users. - +Start by listing all the features you want to develop. For each feature, define its objective, how it aligns with your product goals, and its expected impact on +your users. #### Step 2: Prioritize Features -Not all features are equally important. Prioritize them based on criteria such as user demand, strategic value, and development complexity. This will help you focus on what's most important. - +Not all features are equally important. Prioritize them based on criteria such as user demand, strategic value, and development complexity. This will help you +focus on what's most important. #### Step 3: Estimate Timelines and Resources -For each feature, estimate the development time and the resources required. This includes developer time, dependencies on other features or services, and any other necessary resources. - +For each feature, estimate the development time and the resources required. This includes developer time, dependencies on other features or services, and any +other necessary resources. #### Step 4: Define Milestones Break down each feature into smaller, manageable milestones. Milestones should have clear objectives and deadlines, helping you track progress over time. - #### Step 5: Create the Roadmap Organize the features and milestones into a timeline. This can be done using project management tools, spreadsheets, or specialized roadmap software. - #### Step 6: Review and Adjust Regularly Your roadmap is a living document. Regularly review and adjust it based on progress, changes in priorities, and feedback from stakeholders. - #### Example Code: Tracking a Feature Development Roadmap Below is a simple Python script example that could be used to track the status of features in a development roadmap. @@ -187,483 +222,603 @@ for feature in feature_list: feature.display_feature_info() ``` -This script defines a `Feature` class to track the name, priority, estimated development time, and current status of each feature. It then creates a list of features, updates the status of one, and prints information about all features. This is a basic example to illustrate the concept; in a real-world scenario, you might use more sophisticated project management tools or software. +This script defines a `Feature` class to track the name, priority, estimated development time, and current status of each feature. It then creates a list of +features, updates the status of one, and prints information about all features. This is a basic example to illustrate the concept; in a real-world scenario, you +might use more sophisticated project management tools or software. # kotlin\com\github\simiacryptus\aicoder\actions\code\CustomEditAction.kt -The code provided outlines a Kotlin class `CustomEditAction` that extends a `SelectionAction` for editing code snippets with the help of a virtual API, presumably powered by AI. This class is part of a larger project aimed at enhancing code editing capabilities within an IDE. Based on this context, let's outline a feature development roadmap to expand and improve upon this foundation. - +The code provided outlines a Kotlin class `CustomEditAction` that extends a `SelectionAction` for editing code snippets with the help of a virtual API, +presumably powered by AI. This class is part of a larger project aimed at enhancing code editing capabilities within an IDE. Based on this context, let's +outline a feature development roadmap to expand and improve upon this foundation. #### Phase 1: Core Functionality Enhancement -- **Refine Virtual API Integration**: Improve the interaction with the `VirtualAPI` to support more complex code editing operations, such as refactoring, formatting, and error correction. -- **Expand Language Support**: Currently, the example is hardcoded for Java. Extend support to other popular programming languages like Python, JavaScript, C++, and Go. -- **Improve User Interaction**: Enhance the UI for collecting user instructions, possibly by adding support for voice commands or a more intuitive text-based UI. +- **Refine Virtual API Integration**: Improve the interaction with the `VirtualAPI` to support more complex code editing operations, such as refactoring, + formatting, and error correction. +- **Expand Language Support**: Currently, the example is hardcoded for Java. Extend support to other popular programming languages like Python, JavaScript, C++, + and Go. +- **Improve User Interaction**: Enhance the UI for collecting user instructions, possibly by adding support for voice commands or a more intuitive text-based + UI. #### Phase 2: Intelligence and Learning -- **Adaptive Learning**: Implement machine learning algorithms that allow the system to learn from past edits and user feedback, improving suggestions over time. -- **Contextual Understanding**: Enhance the system's ability to understand the context of the code being edited, including project-specific conventions and patterns. -- **Code Analysis and Suggestions**: Integrate static and dynamic code analysis tools to provide users with suggestions for improving code quality and performance. +- **Adaptive Learning**: Implement machine learning algorithms that allow the system to learn from past edits and user feedback, improving suggestions over + time. +- **Contextual Understanding**: Enhance the system's ability to understand the context of the code being edited, including project-specific conventions and + patterns. +- **Code Analysis and Suggestions**: Integrate static and dynamic code analysis tools to provide users with suggestions for improving code quality and + performance. #### Phase 3: Collaboration and Integration -- **Collaborative Editing Support**: Add features that allow multiple users to collaborate on code editing in real-time, including shared sessions and change tracking. -- **Version Control Integration**: Seamlessly integrate with version control systems like Git, enabling users to make edits and commit changes from within the same interface. -- **IDE Integration**: Expand the plugin to support multiple IDEs and text editors, ensuring a wide range of developers can benefit from the tool. +- **Collaborative Editing Support**: Add features that allow multiple users to collaborate on code editing in real-time, including shared sessions and change + tracking. +- **Version Control Integration**: Seamlessly integrate with version control systems like Git, enabling users to make edits and commit changes from within the + same interface. +- **IDE Integration**: Expand the plugin to support multiple IDEs and text editors, ensuring a wide range of developers can benefit from the tool. #### Phase 4: Advanced Features and Customization + - **Customization and Extensions**: Allow users to create and share their own editing commands and scripts, fostering a community of contributors. - **Advanced Refactoring Tools**: Implement advanced refactoring capabilities, such as architecture-level changes, with AI assistance to ensure correctness. - **Performance Optimization**: Optimize the performance of the tool, ensuring it can handle large codebases and complex edits without significant lag. - #### Phase 5: Security and Privacy + - **Security Enhancements**: Implement robust security measures to protect user code and ensure that all edits are performed in a secure manner. - **Privacy Controls**: Provide users with comprehensive privacy controls, ensuring they have full control over their data and how it's used by the system. - #### Phase 6: User Feedback and Continuous Improvement + - **Feedback Loop**: Establish a structured feedback loop with users to gather insights and suggestions for further improvements. -- **Regular Updates**: Commit to regular updates, incorporating new features, bug fixes, and performance improvements based on user feedback and technological advancements. +- **Regular Updates**: Commit to regular updates, incorporating new features, bug fixes, and performance improvements based on user feedback and technological + advancements. -This roadmap outlines a comprehensive approach to developing a sophisticated code editing tool, focusing on enhancing functionality, intelligence, user experience, and security. +This roadmap outlines a comprehensive approach to developing a sophisticated code editing tool, focusing on enhancing functionality, intelligence, user +experience, and security. # kotlin\com\github\simiacryptus\aicoder\actions\code\CommentsAction.kt -The `CommentsAction` class is part of a larger project aimed at enhancing code readability and understanding through automated comments. This class leverages an AI model via a `ChatProxy` to add explanatory comments to code selections. To further develop this feature and integrate it seamlessly into the user's workflow, a roadmap outlining future enhancements and milestones is essential. Below is a proposed feature development roadmap: - +The `CommentsAction` class is part of a larger project aimed at enhancing code readability and understanding through automated comments. This class leverages an +AI model via a `ChatProxy` to add explanatory comments to code selections. To further develop this feature and integrate it seamlessly into the user's workflow, +a roadmap outlining future enhancements and milestones is essential. Below is a proposed feature development roadmap: #### Phase 1: Core Functionality Enhancement -- **1.1 Improve AI Commenting Accuracy**: Refine the AI model to better understand various programming languages and contexts, ensuring comments are accurate and helpful. -- **1.2 Support for More Languages**: Extend support to include more programming languages, especially those not currently supported, such as scripting languages and domain-specific languages. -- **1.3 User Feedback Loop**: Implement a mechanism for users to provide feedback on the quality of comments, which can be used to train and improve the AI model. +- **1.1 Improve AI Commenting Accuracy**: Refine the AI model to better understand various programming languages and contexts, ensuring comments are accurate + and helpful. +- **1.2 Support for More Languages**: Extend support to include more programming languages, especially those not currently supported, such as scripting + languages and domain-specific languages. +- **1.3 User Feedback Loop**: Implement a mechanism for users to provide feedback on the quality of comments, which can be used to train and improve the AI + model. #### Phase 2: User Experience Improvements -- **2.1 Configurable Commenting Styles**: Allow users to select different commenting styles (e.g., detailed vs. concise) to better match their preferences or project guidelines. -- **2.2 Integration with IDE Features**: Enhance integration with IDE features such as code formatting and refactoring tools to ensure that comments are correctly maintained and updated. -- **2.3 Offline Support**: Develop a lightweight version of the AI model for offline use, catering to users with limited or no internet access. +- **2.1 Configurable Commenting Styles**: Allow users to select different commenting styles (e.g., detailed vs. concise) to better match their preferences or + project guidelines. +- **2.2 Integration with IDE Features**: Enhance integration with IDE features such as code formatting and refactoring tools to ensure that comments are + correctly maintained and updated. +- **2.3 Offline Support**: Develop a lightweight version of the AI model for offline use, catering to users with limited or no internet access. #### Phase 3: Collaboration and Team Use -- **3.1 Team Settings Sync**: Enable teams to synchronize settings for comment styles and preferences across their IDE installations, ensuring consistency in code documentation. -- **3.2 Version Control Integration**: Integrate with version control systems to automatically update comments as part of the code review process, helping reviewers understand changes better. -- **3.3 Comment Translation**: Implement a feature to translate comments into different human languages, facilitating international collaboration. +- **3.1 Team Settings Sync**: Enable teams to synchronize settings for comment styles and preferences across their IDE installations, ensuring consistency in + code documentation. +- **3.2 Version Control Integration**: Integrate with version control systems to automatically update comments as part of the code review process, helping + reviewers understand changes better. +- **3.3 Comment Translation**: Implement a feature to translate comments into different human languages, facilitating international collaboration. #### Phase 4: Advanced Features and Integrations -- **4.1 Code Explanation Summaries**: Beyond line-by-line comments, generate summary explanations for complex code blocks or functions, providing a higher-level understanding. -- **4.2 Educational Mode**: Introduce an educational mode that not only comments on what the code does but also explains why certain programming constructs are used, serving as a learning tool for less experienced developers. -- **4.3 Integration with Documentation Tools**: Automate the generation of external documentation (e.g., API documentation) based on the code and its comments, streamlining the documentation process. +- **4.1 Code Explanation Summaries**: Beyond line-by-line comments, generate summary explanations for complex code blocks or functions, providing a higher-level + understanding. +- **4.2 Educational Mode**: Introduce an educational mode that not only comments on what the code does but also explains why certain programming constructs are + used, serving as a learning tool for less experienced developers. +- **4.3 Integration with Documentation Tools**: Automate the generation of external documentation (e.g., API documentation) based on the code and its comments, + streamlining the documentation process. #### Phase 5: Performance and Scalability -- **5.1 Performance Optimization**: Optimize the performance of the AI model and the plugin, ensuring it works smoothly even in large projects. -- **5.2 Scalability Enhancements**: Ensure the system can scale to support a large number of users and projects, including efficient handling of concurrent commenting requests. +- **5.1 Performance Optimization**: Optimize the performance of the AI model and the plugin, ensuring it works smoothly even in large projects. +- **5.2 Scalability Enhancements**: Ensure the system can scale to support a large number of users and projects, including efficient handling of concurrent + commenting requests. #### Phase 6: Security and Privacy + - **6.1 Secure Data Handling**: Implement robust security measures to protect the code and comments, especially when processed over the network. - **6.2 Privacy Compliance**: Ensure compliance with global privacy regulations, providing users with control over their data. -This roadmap is designed to be iterative, with each phase building upon the successes of the previous ones. Feedback from users and stakeholders will be crucial in prioritizing features and making adjustments as needed. +This roadmap is designed to be iterative, with each phase building upon the successes of the previous ones. Feedback from users and stakeholders will be crucial +in prioritizing features and making adjustments as needed. # kotlin\com\github\simiacryptus\aicoder\actions\code\DescribeAction.kt -The `DescribeAction` class is part of a larger project aimed at enhancing code understanding and documentation through automated descriptions. This class leverages a virtual API to generate human-readable descriptions of code snippets in various programming languages. The roadmap for developing and enhancing this feature can be outlined in several stages, focusing on expanding capabilities, improving accuracy, and integrating user feedback. - +The `DescribeAction` class is part of a larger project aimed at enhancing code understanding and documentation through automated descriptions. This class +leverages a virtual API to generate human-readable descriptions of code snippets in various programming languages. The roadmap for developing and enhancing this +feature can be outlined in several stages, focusing on expanding capabilities, improving accuracy, and integrating user feedback. #### Phase 1: Initial Development and Testing -- **Implement Basic Functionality**: Complete the initial setup of the `DescribeAction` class, ensuring it can communicate with the virtual API and return basic descriptions. + +- **Implement Basic Functionality**: Complete the initial setup of the `DescribeAction` class, ensuring it can communicate with the virtual API and return basic + descriptions. - **Support for Major Languages**: Ensure the feature supports major programming languages such as Java, Python, C++, and JavaScript. - **Integration Testing**: Test the integration with the IDE, focusing on how the feature interacts with different types of code selections and languages. -- **User Interface Design**: Develop a simple, intuitive interface for users to interact with the feature, including configuring settings and viewing descriptions. - +- **User Interface Design**: Develop a simple, intuitive interface for users to interact with the feature, including configuring settings and viewing + descriptions. #### Phase 2: Enhancement and Expansion + - **Language Support Expansion**: Gradually add support for more programming languages based on user demand and the availability of language models. -- **Improve Description Accuracy**: Utilize feedback loops and machine learning to refine the descriptions generated, making them more accurate and context-aware. +- **Improve Description Accuracy**: Utilize feedback loops and machine learning to refine the descriptions generated, making them more accurate and + context-aware. - **Customization Features**: Allow users to customize the verbosity of descriptions, the style of comments, and other preferences to better fit their workflow. -- **Performance Optimization**: Optimize the code to reduce latency in fetching descriptions and ensure the feature does not significantly impact IDE performance. - +- **Performance Optimization**: Optimize the code to reduce latency in fetching descriptions and ensure the feature does not significantly impact IDE + performance. #### Phase 3: Advanced Features and Integration + - **Code Summarization**: Beyond single selections, implement functionality to generate summaries for entire files or projects. -- **Contextual Awareness**: Enhance the feature to consider more context about the code, such as surrounding functions or classes, to provide more insightful descriptions. +- **Contextual Awareness**: Enhance the feature to consider more context about the code, such as surrounding functions or classes, to provide more insightful + descriptions. - **Collaboration Tools**: Integrate with version control systems to automatically generate descriptions for code changes in pull requests or commits. - **Offline Support**: Explore possibilities for offline support, allowing basic functionality without needing to communicate with the virtual API. - #### Phase 4: User Feedback and Continuous Improvement -- **User Feedback Loop**: Establish mechanisms for collecting user feedback directly through the IDE plugin, focusing on the usefulness and accuracy of descriptions. + +- **User Feedback Loop**: Establish mechanisms for collecting user feedback directly through the IDE plugin, focusing on the usefulness and accuracy of + descriptions. - **Continuous Learning**: Implement machine learning techniques to continuously improve the quality of descriptions based on user interactions and feedback. - **Documentation and Tutorials**: Create comprehensive documentation and tutorials to help users get the most out of the feature. - **Community Engagement**: Engage with the developer community to gather insights, beta testers, and contributors to further refine and expand the feature. - #### Phase 5: Future Directions -- **AI-Assisted Coding**: Explore the integration of AI-assisted coding features, suggesting improvements or alternative implementations based on the described code. -- **Language Model Training**: Consider developing custom language models tailored to specific domains or technologies to provide even more relevant descriptions. -- **Expansion to Other IDEs**: Look into the possibility of porting the feature to other popular IDEs, expanding the user base and gathering more diverse feedback. -This roadmap outlines a comprehensive approach to developing the `DescribeAction` feature, from its initial implementation to becoming a sophisticated tool for code documentation and understanding. Each phase builds upon the last, gradually enhancing the feature's capabilities and integrating valuable user feedback to ensure it meets the needs of a wide range of developers. +- **AI-Assisted Coding**: Explore the integration of AI-assisted coding features, suggesting improvements or alternative implementations based on the described + code. +- **Language Model Training**: Consider developing custom language models tailored to specific domains or technologies to provide even more relevant + descriptions. +- **Expansion to Other IDEs**: Look into the possibility of porting the feature to other popular IDEs, expanding the user base and gathering more diverse + feedback. -# kotlin\com\github\simiacryptus\aicoder\actions\code\ImplementStubAction.kt +This roadmap outlines a comprehensive approach to developing the `DescribeAction` feature, from its initial implementation to becoming a sophisticated tool for +code documentation and understanding. Each phase builds upon the last, gradually enhancing the feature's capabilities and integrating valuable user feedback to +ensure it meets the needs of a wide range of developers. -The `ImplementStubAction` class is part of a larger project aimed at enhancing code editing and generation capabilities within an IDE, leveraging AI technologies. The roadmap for developing and enhancing this feature can be structured into several key phases, each focusing on specific aspects of functionality, performance, and user experience. Below is a proposed feature development roadmap: +# kotlin\com\github\simiacryptus\aicoder\actions\code\ImplementStubAction.kt +The `ImplementStubAction` class is part of a larger project aimed at enhancing code editing and generation capabilities within an IDE, leveraging AI +technologies. The roadmap for developing and enhancing this feature can be structured into several key phases, each focusing on specific aspects of +functionality, performance, and user experience. Below is a proposed feature development roadmap: #### Phase 1: Foundation and Core Functionality -- **Initial Setup and Integration**: Establish the basic framework for the `ImplementStubAction` class, ensuring it integrates seamlessly with the existing project infrastructure. -- **VirtualAPI Interface Development**: Develop and refine the `VirtualAPI` interface to support code editing operations, focusing on the `editCode` method for implementing stubs. + +- **Initial Setup and Integration**: Establish the basic framework for the `ImplementStubAction` class, ensuring it integrates seamlessly with the existing + project infrastructure. +- **VirtualAPI Interface Development**: Develop and refine the `VirtualAPI` interface to support code editing operations, focusing on the `editCode` method for + implementing stubs. - **Proxy Configuration**: Implement the `getProxy` method to correctly instantiate and configure the `ChatProxy` for communicating with the AI model. - **Language Support Determination**: Enhance the `isLanguageSupported` method to accurately identify supported programming languages, excluding plain text. - #### Phase 2: Selection and Processing Enhancements -- **Selection Optimization**: Improve the `defaultSelection` method to more accurately determine the optimal code selection for stub implementation based on the editor state. -- **Code Context Analysis**: Refine the process of identifying the smallest intersecting method within the selected code context to ensure accurate stub implementation. -- **Code Editing and Generation**: Optimize the `processSelection` method to effectively generate and implement code stubs using the AI model, focusing on accuracy and relevance. +- **Selection Optimization**: Improve the `defaultSelection` method to more accurately determine the optimal code selection for stub implementation based on the + editor state. +- **Code Context Analysis**: Refine the process of identifying the smallest intersecting method within the selected code context to ensure accurate stub + implementation. +- **Code Editing and Generation**: Optimize the `processSelection` method to effectively generate and implement code stubs using the AI model, focusing on + accuracy and relevance. #### Phase 3: User Experience and Customization -- **Configuration Options**: Develop a user-friendly configuration interface allowing users to customize settings such as the AI model, temperature, and human language preference. + +- **Configuration Options**: Develop a user-friendly configuration interface allowing users to customize settings such as the AI model, temperature, and human + language preference. - **Feedback Mechanism**: Implement a feedback mechanism within the IDE plugin to collect user input on the accuracy and usefulness of generated code stubs. - **Performance Optimization**: Analyze and optimize performance to reduce latency in code generation and ensure a smooth user experience. - #### Phase 4: Advanced Features and Integration + - **Multi-Language Support**: Expand the range of supported programming languages, potentially incorporating feedback from the user community. - **Contextual Awareness**: Enhance the AI model's understanding of code context and project-specific nuances to improve the relevance of generated code. -- **Integration with Other Tools**: Explore integration possibilities with other IDE features and plugins, such as version control systems and code quality tools. - +- **Integration with Other Tools**: Explore integration possibilities with other IDE features and plugins, such as version control systems and code quality + tools. #### Phase 5: Testing, Documentation, and Release -- **Comprehensive Testing**: Conduct thorough testing, including unit tests, integration tests, and user acceptance testing, to ensure reliability and functionality. + +- **Comprehensive Testing**: Conduct thorough testing, including unit tests, integration tests, and user acceptance testing, to ensure reliability and + functionality. - **Documentation**: Prepare detailed documentation covering setup, usage, customization options, and troubleshooting. - **Release and Promotion**: Officially release the updated feature, accompanied by promotional activities to encourage adoption by the target user base. - #### Phase 6: Feedback and Continuous Improvement + - **User Feedback Collection**: Actively collect and analyze user feedback on the feature's functionality and usability. -- **Iterative Improvements**: Based on feedback and observed usage patterns, make iterative improvements to the feature, addressing any identified issues and incorporating new capabilities. +- **Iterative Improvements**: Based on feedback and observed usage patterns, make iterative improvements to the feature, addressing any identified issues and + incorporating new capabilities. -This roadmap provides a structured approach to developing the `ImplementStubAction` feature, focusing on delivering a powerful, user-friendly tool that enhances the coding experience within an IDE. +This roadmap provides a structured approach to developing the `ImplementStubAction` feature, focusing on delivering a powerful, user-friendly tool that enhances +the coding experience within an IDE. # kotlin\com\github\simiacryptus\aicoder\actions\code\DocAction.kt - #### Feature Development Roadmap for `DocAction` Class -The `DocAction` class is designed to automatically generate documentation for code blocks within a project. It leverages a virtual API to process code and generate corresponding documentation in a specified human language. Below is a roadmap outlining the planned features and improvements to enhance its functionality, usability, and integration capabilities. - +The `DocAction` class is designed to automatically generate documentation for code blocks within a project. It leverages a virtual API to process code and +generate corresponding documentation in a specified human language. Below is a roadmap outlining the planned features and improvements to enhance its +functionality, usability, and integration capabilities. ##### Phase 1: Core Functionality Enhancement -- **Refinement of Virtual API Integration**: Enhance the integration with the `DocAction_VirtualAPI` to support more complex code structures and languages. This includes improving the accuracy and relevance of generated documentation. -- **Support for Additional Languages**: Extend support to more programming languages beyond Kotlin, ensuring the tool can be used across a wider range of projects. -- **Customization of Documentation Style**: Allow users to customize the style of generated documentation, including the ability to specify comment formats, verbosity, and inclusion of examples. +- **Refinement of Virtual API Integration**: Enhance the integration with the `DocAction_VirtualAPI` to support more complex code structures and languages. This + includes improving the accuracy and relevance of generated documentation. +- **Support for Additional Languages**: Extend support to more programming languages beyond Kotlin, ensuring the tool can be used across a wider range of + projects. +- **Customization of Documentation Style**: Allow users to customize the style of generated documentation, including the ability to specify comment formats, + verbosity, and inclusion of examples. ##### Phase 2: Usability Improvements -- **GUI for Configuration Settings**: Develop a graphical user interface within the IDE for configuring `DocAction` settings, such as default human language, documentation style preferences, and API settings. -- **Interactive Documentation Editing**: Implement a feature that allows users to edit generated documentation directly within the IDE before finalizing it, providing suggestions and corrections in real-time. -- **Documentation Preview**: Introduce a preview feature that lets users see how the generated documentation will look in their code before applying it. +- **GUI for Configuration Settings**: Develop a graphical user interface within the IDE for configuring `DocAction` settings, such as default human language, + documentation style preferences, and API settings. +- **Interactive Documentation Editing**: Implement a feature that allows users to edit generated documentation directly within the IDE before finalizing it, + providing suggestions and corrections in real-time. +- **Documentation Preview**: Introduce a preview feature that lets users see how the generated documentation will look in their code before applying it. ##### Phase 3: Advanced Features -- **Batch Documentation Generation**: Add the capability to generate documentation for multiple code blocks or entire files at once, improving efficiency for large projects. -- **Context-Aware Documentation**: Enhance the AI model to consider the broader context of the codebase, generating documentation that is not only accurate but also consistent with existing comments and documentation style. -- **Integration with Version Control Systems**: Implement features that facilitate the integration with version control systems, such as Git, to automatically generate or update documentation as part of the commit process. +- **Batch Documentation Generation**: Add the capability to generate documentation for multiple code blocks or entire files at once, improving efficiency for + large projects. +- **Context-Aware Documentation**: Enhance the AI model to consider the broader context of the codebase, generating documentation that is not only accurate but + also consistent with existing comments and documentation style. +- **Integration with Version Control Systems**: Implement features that facilitate the integration with version control systems, such as Git, to automatically + generate or update documentation as part of the commit process. ##### Phase 4: Performance and Scalability -- **Optimization for Large Projects**: Optimize performance to handle large codebases efficiently, reducing processing time and memory usage. -- **Scalability of Virtual API**: Ensure the backend API can scale to support a growing number of requests as the tool gains popularity and is used in larger projects. +- **Optimization for Large Projects**: Optimize performance to handle large codebases efficiently, reducing processing time and memory usage. +- **Scalability of Virtual API**: Ensure the backend API can scale to support a growing number of requests as the tool gains popularity and is used in larger + projects. ##### Phase 5: Community and Open Source Contribution -- **Plugin Extensibility**: Develop an API or plugin system that allows third-party developers to extend the functionality of `DocAction`, such as adding support for new languages or documentation styles. -- **Open Source Contribution Guidelines**: Establish guidelines and a framework for the community to contribute to the development of `DocAction`, including feature enhancements, bug fixes, and language support. +- **Plugin Extensibility**: Develop an API or plugin system that allows third-party developers to extend the functionality of `DocAction`, such as adding + support for new languages or documentation styles. +- **Open Source Contribution Guidelines**: Establish guidelines and a framework for the community to contribute to the development of `DocAction`, including + feature enhancements, bug fixes, and language support. ##### Phase 6: Continuous Improvement and Maintenance -- **Regular Updates to AI Model**: Continuously train and update the AI model to improve documentation quality and support new programming paradigms and languages. -- **User Feedback Loop**: Implement a system for collecting user feedback directly through the IDE plugin, using this input to guide future development priorities and improvements. -This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The goal is to make `DocAction` a versatile, user-friendly tool that significantly simplifies the documentation process for developers. +- **Regular Updates to AI Model**: Continuously train and update the AI model to improve documentation quality and support new programming paradigms and + languages. +- **User Feedback Loop**: Implement a system for collecting user feedback directly through the IDE plugin, using this input to guide future development + priorities and improvements. -# kotlin\com\github\simiacryptus\aicoder\actions\code\PasteAction.kt +This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The goal is to make `DocAction` a versatile, +user-friendly tool that significantly simplifies the documentation process for developers. -To create a feature development roadmap for the `PasteAction` class and its associated functionalities, we will outline the current capabilities, identify potential enhancements, and prioritize these enhancements based on their impact and feasibility. This roadmap aims to guide the development process, ensuring that the `PasteAction` class evolves to meet user needs more effectively. +# kotlin\com\github\simiacryptus\aicoder\actions\code\PasteAction.kt +To create a feature development roadmap for the `PasteAction` class and its associated functionalities, we will outline the current capabilities, identify +potential enhancements, and prioritize these enhancements based on their impact and feasibility. This roadmap aims to guide the development process, ensuring +that the `PasteAction` class evolves to meet user needs more effectively. #### Current Capabilities + 1. **Clipboard Content Handling**: The class can access and retrieve content from the system clipboard, supporting plain text data flavors. -2. **Language Detection and Conversion**: It can detect the language of the clipboard content (assuming text) and convert it to a specified programming language using an external API. +2. **Language Detection and Conversion**: It can detect the language of the clipboard content (assuming text) and convert it to a specified programming language + using an external API. 3. **Integration with External API**: Utilizes a `ChatProxy` to interact with a `VirtualAPI` for the conversion of text. 4. **IDE Integration**: Designed to work within an IDE (IntelliJ), providing actions based on the IDE's context and project settings. - #### Short-term Enhancements (1-3 Months) -1. **Improved Language Detection**: Enhance the autodetect feature for more accurate language detection, possibly by integrating more advanced machine learning models. -2. **Support for More Languages**: Expand the list of supported languages for conversion, based on user demand and the capabilities of the underlying `VirtualAPI`. -3. **User Interface Improvements**: Develop a more intuitive interface for selecting the target language for conversion, including a dropdown menu within the IDE. -4. **Performance Optimization**: Optimize the process of fetching and converting clipboard content to reduce latency and improve user experience. +1. **Improved Language Detection**: Enhance the autodetect feature for more accurate language detection, possibly by integrating more advanced machine learning + models. +2. **Support for More Languages**: Expand the list of supported languages for conversion, based on user demand and the capabilities of the underlying + `VirtualAPI`. +3. **User Interface Improvements**: Develop a more intuitive interface for selecting the target language for conversion, including a dropdown menu within the + IDE. +4. **Performance Optimization**: Optimize the process of fetching and converting clipboard content to reduce latency and improve user experience. #### Mid-term Enhancements (4-6 Months) + 1. **Bidirectional Conversion**: Allow for the conversion of code between two specified languages, not just from clipboard content to a target language. 2. **Integration with More APIs**: To improve conversion accuracy and support for languages, integrate with additional APIs or services. 3. **Custom Conversion Rules**: Allow users to define custom rules or preferences for code conversion, accommodating specific coding standards or practices. -4. **Clipboard Monitoring**: Implement an optional feature to monitor clipboard content and automatically suggest conversions based on detected programming languages. - +4. **Clipboard Monitoring**: Implement an optional feature to monitor clipboard content and automatically suggest conversions based on detected programming + languages. #### Long-term Enhancements (7-12 Months) -1. **Machine Learning Model Training**: Develop and train custom machine learning models for language detection and conversion, tailored to the specific needs and data of the users. -2. **Plugin Ecosystem**: Create a framework allowing third-party developers to extend the functionality of the `PasteAction` class, such as adding support for new languages or conversion services. -3. **Collaborative Features**: Introduce features that allow teams to share and manage conversion preferences and custom rules, facilitating consistency across a project or organization. -4. **Comprehensive Documentation and Tutorials**: Develop detailed documentation and tutorials to help users maximize the utility of the `PasteAction` class and its features. +1. **Machine Learning Model Training**: Develop and train custom machine learning models for language detection and conversion, tailored to the specific needs + and data of the users. +2. **Plugin Ecosystem**: Create a framework allowing third-party developers to extend the functionality of the `PasteAction` class, such as adding support for + new languages or conversion services. +3. **Collaborative Features**: Introduce features that allow teams to share and manage conversion preferences and custom rules, facilitating consistency across + a project or organization. +4. **Comprehensive Documentation and Tutorials**: Develop detailed documentation and tutorials to help users maximize the utility of the `PasteAction` class and + its features. #### Prioritization -The roadmap prioritizes enhancements that directly improve user experience and broaden the utility of the `PasteAction` class. Short-term goals focus on immediate usability and performance improvements. Mid-term goals aim to expand functionality and integration options. Long-term goals are centered around customization, collaboration, and creating a more robust and adaptable tool. -This roadmap is subject to change based on user feedback, technological advancements, and strategic shifts in project focus. Regular reviews and updates to the roadmap will ensure that development efforts remain aligned with user needs and industry trends. +The roadmap prioritizes enhancements that directly improve user experience and broaden the utility of the `PasteAction` class. Short-term goals focus on +immediate usability and performance improvements. Mid-term goals aim to expand functionality and integration options. Long-term goals are centered around +customization, collaboration, and creating a more robust and adaptable tool. -# kotlin\com\github\simiacryptus\aicoder\actions\code\InsertImplementationAction.kt +This roadmap is subject to change based on user feedback, technological advancements, and strategic shifts in project focus. Regular reviews and updates to the +roadmap will ensure that development efforts remain aligned with user needs and industry trends. +# kotlin\com\github\simiacryptus\aicoder\actions\code\InsertImplementationAction.kt #### Feature Development Roadmap for `InsertImplementationAction` -The `InsertImplementationAction` class is designed to enhance the coding experience by automatically generating code implementations based on comments or selected text within the IDE. This roadmap outlines the planned features and improvements to make this tool more robust, user-friendly, and versatile. - +The `InsertImplementationAction` class is designed to enhance the coding experience by automatically generating code implementations based on comments or +selected text within the IDE. This roadmap outlines the planned features and improvements to make this tool more robust, user-friendly, and versatile. ##### Phase 1: Core Functionality Enhancements 1. **Improved Code Generation Accuracy** - - Implement advanced NLP models to better understand the context and intent behind comments or selected text. - - Integrate with multiple code generation APIs to compare and choose the best-generated code snippet. + +- Implement advanced NLP models to better understand the context and intent behind comments or selected text. +- Integrate with multiple code generation APIs to compare and choose the best-generated code snippet. 2. **Support for More Programming Languages** - - Extend the current support to include more programming languages, focusing on those most requested by the community. - - Develop language-specific plugins to handle idiomatic nuances better. + +- Extend the current support to include more programming languages, focusing on those most requested by the community. +- Develop language-specific plugins to handle idiomatic nuances better. 3. **Enhanced Context Understanding** - - Improve the extraction and interpretation of the surrounding code context to generate more relevant code snippets. - - Use the entire file or project context where necessary to understand broader requirements. +- Improve the extraction and interpretation of the surrounding code context to generate more relevant code snippets. +- Use the entire file or project context where necessary to understand broader requirements. ##### Phase 2: User Experience Improvements 1. **Configurable Preferences** - - Allow users to set preferences for code style, documentation, and error handling patterns. - - Enable project-specific configurations to cater to different coding standards and practices. + +- Allow users to set preferences for code style, documentation, and error handling patterns. +- Enable project-specific configurations to cater to different coding standards and practices. 2. **Interactive Code Generation** - - Introduce an interactive mode where users can guide the code generation process through choices or corrections. - - Implement feedback loops where the tool learns from user corrections to improve future suggestions. + +- Introduce an interactive mode where users can guide the code generation process through choices or corrections. +- Implement feedback loops where the tool learns from user corrections to improve future suggestions. 3. **Integration with Version Control Systems** - - Develop features to automatically create branches or pull requests with generated code for review. - - Provide options to compare generated code with existing implementations to assess novelty and relevance. +- Develop features to automatically create branches or pull requests with generated code for review. +- Provide options to compare generated code with existing implementations to assess novelty and relevance. ##### Phase 3: Advanced Features and Integrations 1. **Code Refactoring Suggestions** - - Analyze existing code to suggest refactoring opportunities where generated code could simplify or optimize the current implementation. - - Offer automated refactoring tools guided by the generated code suggestions. + +- Analyze existing code to suggest refactoring opportunities where generated code could simplify or optimize the current implementation. +- Offer automated refactoring tools guided by the generated code suggestions. 2. **Integration with Code Review Tools** - - Connect with code review platforms to suggest generated code during the review process, helping reviewers offer concrete improvement suggestions. - - Implement a review mode where generated code is specifically tailored to address review comments. + +- Connect with code review platforms to suggest generated code during the review process, helping reviewers offer concrete improvement suggestions. +- Implement a review mode where generated code is specifically tailored to address review comments. 3. **Collaboration and Sharing** - - Enable users to share their generated code snippets with the community, fostering a collaborative environment for improvement and innovation. - - Create a repository of user-approved code snippets that can be directly inserted into projects. +- Enable users to share their generated code snippets with the community, fostering a collaborative environment for improvement and innovation. +- Create a repository of user-approved code snippets that can be directly inserted into projects. ##### Phase 4: Scalability and Performance Optimization 1. **Caching and Performance Improvements** - - Implement caching mechanisms for frequently requested code generation to reduce latency and improve responsiveness. - - Optimize the code generation pipeline for speed and efficiency, especially for large projects. + +- Implement caching mechanisms for frequently requested code generation to reduce latency and improve responsiveness. +- Optimize the code generation pipeline for speed and efficiency, especially for large projects. 2. **Scalable Architecture** - - Design the backend to efficiently handle a growing number of requests and support concurrent code generation tasks. - - Ensure the system is robust and can scale horizontally to meet increasing demand. + +- Design the backend to efficiently handle a growing number of requests and support concurrent code generation tasks. +- Ensure the system is robust and can scale horizontally to meet increasing demand. 3. **Monitoring and Analytics** - - Integrate monitoring tools to track usage patterns, performance metrics, and error rates. - - Use analytics to understand feature usage and prioritize future development efforts based on user needs. -This roadmap is subject to change based on user feedback and technological advancements. The ultimate goal is to create a highly efficient, user-friendly, and versatile tool that significantly enhances the coding experience by automating routine tasks and fostering innovation. +- Integrate monitoring tools to track usage patterns, performance metrics, and error rates. +- Use analytics to understand feature usage and prioritize future development efforts based on user needs. -# kotlin\com\github\simiacryptus\aicoder\actions\code\RecentCodeEditsAction.kt +This roadmap is subject to change based on user feedback and technological advancements. The ultimate goal is to create a highly efficient, user-friendly, and +versatile tool that significantly enhances the coding experience by automating routine tasks and fostering innovation. +# kotlin\com\github\simiacryptus\aicoder\actions\code\RecentCodeEditsAction.kt #### Feature Development Roadmap for RecentCodeEditsAction -The `RecentCodeEditsAction` class is designed to enhance the developer experience within an IDE by providing quick access to a list of recent custom code edits. This roadmap outlines the planned features and improvements to make this tool more robust, user-friendly, and integrated with the development environment. - +The `RecentCodeEditsAction` class is designed to enhance the developer experience within an IDE by providing quick access to a list of recent custom code edits. +This roadmap outlines the planned features and improvements to make this tool more robust, user-friendly, and integrated with the development environment. ##### Phase 1: Core Functionality Enhancements 1. **Improved Command History Management** - - Implement a more sophisticated algorithm for tracking and prioritizing the history of custom edits based on frequency and recency of use. - - Allow users to manually pin/unpin commands in the history for easier access. + +- Implement a more sophisticated algorithm for tracking and prioritizing the history of custom edits based on frequency and recency of use. +- Allow users to manually pin/unpin commands in the history for easier access. 2. **Dynamic Context Sensitivity** - - Enhance the action to be context-sensitive, showing relevant code edits based on the current file type or project context. + +- Enhance the action to be context-sensitive, showing relevant code edits based on the current file type or project context. 3. **UI/UX Improvements** - - Introduce a cleaner, more intuitive UI for displaying the list of commands. - - Implement keyboard shortcuts for faster navigation and selection of recent edits. +- Introduce a cleaner, more intuitive UI for displaying the list of commands. +- Implement keyboard shortcuts for faster navigation and selection of recent edits. ##### Phase 2: Integration and Compatibility 1. **Cross-Project Command Sharing** - - Enable sharing of custom edit commands across different projects within the same IDE instance. - - Implement a feature to export/import command sets for use in different environments or by different users. + +- Enable sharing of custom edit commands across different projects within the same IDE instance. +- Implement a feature to export/import command sets for use in different environments or by different users. 2. **Support for Multiple Languages** - - Extend the functionality to support multiple programming languages, adapting the available commands based on the language of the current file. + +- Extend the functionality to support multiple programming languages, adapting the available commands based on the language of the current file. 3. **Version Control System (VCS) Integration** - - Integrate with VCS to allow users to mark edits related to specific commits or branches, facilitating easier code reviews and collaboration. +- Integrate with VCS to allow users to mark edits related to specific commits or branches, facilitating easier code reviews and collaboration. ##### Phase 3: Advanced Features 1. **AI-Assisted Code Edits** - - Incorporate AI-based suggestions for code edits based on the current project context and past user behavior. - - Implement a feedback mechanism for users to improve AI suggestions over time. + +- Incorporate AI-based suggestions for code edits based on the current project context and past user behavior. +- Implement a feedback mechanism for users to improve AI suggestions over time. 2. **Custom Edit Scripting** - - Allow users to create more complex custom edit commands using a simple scripting language. - - Provide a library of script templates for common tasks to help users get started. + +- Allow users to create more complex custom edit commands using a simple scripting language. +- Provide a library of script templates for common tasks to help users get started. 3. **Performance Optimization** - - Optimize the performance of the action, ensuring it remains responsive even with a large history of commands or in large projects. + +- Optimize the performance of the action, ensuring it remains responsive even with a large history of commands or in large projects. 4. **Analytics and Insights** - - Offer analytics on the usage of custom edits, helping users identify patterns and optimize their workflow. - - Provide insights and recommendations based on analysis of common edits and user behavior. +- Offer analytics on the usage of custom edits, helping users identify patterns and optimize their workflow. +- Provide insights and recommendations based on analysis of common edits and user behavior. ##### Phase 4: Community and Collaboration 1. **Community Sharing Platform** - - Develop a platform for users to share, rate, and comment on custom edit scripts. - - Implement a system for discovering and incorporating highly-rated community scripts into the user's IDE. + +- Develop a platform for users to share, rate, and comment on custom edit scripts. +- Implement a system for discovering and incorporating highly-rated community scripts into the user's IDE. 2. **Collaborative Editing Sessions** - - Enable real-time collaborative editing sessions where users can apply custom edits together, facilitating pair programming and team code reviews. + +- Enable real-time collaborative editing sessions where users can apply custom edits together, facilitating pair programming and team code reviews. 3. **Feedback and Continuous Improvement** - - Establish a feedback loop with the user community to continuously gather suggestions and improve the tool. - - Regularly update the tool with new features and improvements based on user feedback and emerging development trends. -By following this roadmap, the `RecentCodeEditsAction` can evolve into a powerful tool that significantly enhances coding efficiency and collaboration within the IDE environment. +- Establish a feedback loop with the user community to continuously gather suggestions and improve the tool. +- Regularly update the tool with new features and improvements based on user feedback and emerging development trends. -# kotlin\com\github\simiacryptus\aicoder\actions\dev\AppServer.kt +By following this roadmap, the `RecentCodeEditsAction` can evolve into a powerful tool that significantly enhances coding efficiency and collaboration within +the IDE environment. -Creating a feature development roadmap for the `AppServer` class involves outlining the future enhancements, optimizations, and functionalities that can be added to improve its performance, usability, and integration capabilities. Here's a proposed roadmap: +# kotlin\com\github\simiacryptus\aicoder\actions\dev\AppServer.kt +Creating a feature development roadmap for the `AppServer` class involves outlining the future enhancements, optimizations, and functionalities that can be +added to improve its performance, usability, and integration capabilities. Here's a proposed roadmap: #### Phase 1: Core Functionality Enhancements + - **Security Enhancements**: Implement SSL/TLS support to ensure secure communication between the server and clients. - **Dynamic Context Management**: Develop the ability to dynamically add or remove application contexts without needing to restart the server. - **Performance Optimization**: Profile the server under various loads to identify bottlenecks and optimize for better performance and scalability. - #### Phase 2: Usability Improvements -- **Dashboard for Server Management**: Create a web-based dashboard for monitoring server status, managing applications, and viewing logs in real-time. -- **Configuration UI**: Develop a graphical interface for configuring server settings, such as port numbers, context paths, and SSL certificates, without directly modifying the code or configuration files. -- **Documentation and Examples**: Provide comprehensive documentation and example projects demonstrating how to use the server for different types of applications. +- **Dashboard for Server Management**: Create a web-based dashboard for monitoring server status, managing applications, and viewing logs in real-time. +- **Configuration UI**: Develop a graphical interface for configuring server settings, such as port numbers, context paths, and SSL certificates, without + directly modifying the code or configuration files. +- **Documentation and Examples**: Provide comprehensive documentation and example projects demonstrating how to use the server for different types of + applications. #### Phase 3: Integration and Extensibility -- **Plugin Architecture**: Implement a plugin system that allows developers to extend the server's functionality, such as adding new types of handlers or integrating with other services. + +- **Plugin Architecture**: Implement a plugin system that allows developers to extend the server's functionality, such as adding new types of handlers or + integrating with other services. - **REST API for Server Control**: Expose a REST API for programmatically controlling the server, including starting, stopping, and deploying applications. - **WebSocket Enhancements**: Enhance WebSocket support with features like message broadcasting, rooms/channels, and connection management. - #### Phase 4: Advanced Features -- **Load Balancing and Failover**: Introduce load balancing capabilities and support for failover to enhance reliability and support high-availability deployments. -- **Microservices Support**: Add features to facilitate the development and deployment of microservices, including service discovery and inter-service communication. -- **Containerization and Orchestration**: Provide support for running the server in containerized environments like Docker and orchestration with Kubernetes, including Helm charts for easy deployment. +- **Load Balancing and Failover**: Introduce load balancing capabilities and support for failover to enhance reliability and support high-availability + deployments. +- **Microservices Support**: Add features to facilitate the development and deployment of microservices, including service discovery and inter-service + communication. +- **Containerization and Orchestration**: Provide support for running the server in containerized environments like Docker and orchestration with Kubernetes, + including Helm charts for easy deployment. #### Phase 5: Community and Ecosystem + - **Community Building**: Establish a community forum and contribution guidelines to encourage external contributions and feedback. - **Marketplace for Plugins**: Create a marketplace for sharing and discovering plugins developed by the community. -- **Integration with IDEs**: Develop plugins for popular IDEs (e.g., IntelliJ IDEA, Eclipse) to allow developers to manage their server and applications directly from the IDE. - +- **Integration with IDEs**: Develop plugins for popular IDEs (e.g., IntelliJ IDEA, Eclipse) to allow developers to manage their server and applications + directly from the IDE. #### Phase 6: Continuous Improvement -- **Automated Testing and CI/CD**: Set up automated testing frameworks and continuous integration/continuous deployment pipelines to ensure code quality and streamline releases. + +- **Automated Testing and CI/CD**: Set up automated testing frameworks and continuous integration/continuous deployment pipelines to ensure code quality and + streamline releases. - **Internationalization and Localization**: Support multiple languages in the server's UI to cater to a global user base. - **Accessibility Improvements**: Ensure that the server's management dashboard and documentation are accessible to users with disabilities. -This roadmap is designed to be iterative, with each phase building upon the previous ones. Prioritization of these features should be based on user feedback, market demand, and the strategic goals of the project. +This roadmap is designed to be iterative, with each phase building upon the previous ones. Prioritization of these features should be based on user feedback, +market demand, and the strategic goals of the project. # kotlin\com\github\simiacryptus\aicoder\actions\code\RenameVariablesAction.kt -The `RenameVariablesAction` class is part of a larger project aimed at enhancing code editing and refactoring capabilities within an IDE, leveraging AI to suggest variable name changes for better code readability and maintainability. The development roadmap for this feature, and potentially related features, can be outlined in several stages to ensure a structured and efficient implementation process. - +The `RenameVariablesAction` class is part of a larger project aimed at enhancing code editing and refactoring capabilities within an IDE, leveraging AI to +suggest variable name changes for better code readability and maintainability. The development roadmap for this feature, and potentially related features, can +be outlined in several stages to ensure a structured and efficient implementation process. #### Phase 1: Initial Setup and Basic Functionality + - **Task 1.1:** Set up the project environment and ensure all necessary dependencies are integrated, including the AI model and IDE plugin development kits. -- **Task 1.2:** Implement the basic structure of the `RenameVariablesAction` class, focusing on integrating the AI model to suggest variable renames based on the code context. +- **Task 1.2:** Implement the basic structure of the `RenameVariablesAction` class, focusing on integrating the AI model to suggest variable renames based on + the code context. - **Task 1.3:** Develop the `RenameAPI` interface and its `SuggestionResponse` inner class to handle communication with the AI model effectively. - **Task 1.4:** Implement a basic UI dialog to display rename suggestions to the user and allow them to select which variables to rename. - #### Phase 2: Enhancement and Testing + - **Task 2.1:** Enhance the AI model's accuracy in suggesting variable names by training it on a larger dataset or refining its parameters. - **Task 2.2:** Implement additional filters and checks to ensure that suggested variable names do not conflict with existing names or reserved keywords. -- **Task 2.3:** Conduct thorough testing, including unit tests for the `RenameVariablesAction` and `RenameAPI` classes and integration tests to ensure the feature works seamlessly within the IDE. +- **Task 2.3:** Conduct thorough testing, including unit tests for the `RenameVariablesAction` and `RenameAPI` classes and integration tests to ensure the + feature works seamlessly within the IDE. - **Task 2.4:** Collect user feedback on the initial release and identify areas for improvement or additional features requested by users. - #### Phase 3: Advanced Features and Integration + - **Task 3.1:** Based on user feedback, implement advanced features such as the ability to rename variables across multiple files or projects. - **Task 3.2:** Integrate the rename feature with other refactoring tools within the IDE, allowing for a more comprehensive code refactoring experience. -- **Task 3.3:** Enhance the UI to include more detailed information about the suggested renames, such as the reason behind each suggestion or its impact on code readability. +- **Task 3.3:** Enhance the UI to include more detailed information about the suggested renames, such as the reason behind each suggestion or its impact on code + readability. - **Task 3.4:** Explore the possibility of extending the feature to support other languages or IDEs, increasing the tool's versatility and user base. - #### Phase 4: Optimization and Finalization + - **Task 4.1:** Optimize the performance of the rename feature, ensuring it runs efficiently even on large codebases. - **Task 4.2:** Finalize the documentation, including detailed user guides and API documentation for developers looking to extend or integrate the feature. - **Task 4.3:** Implement a feedback loop within the tool, allowing users to report issues or suggest improvements directly through the IDE. - **Task 4.4:** Release the final version of the feature, accompanied by a marketing campaign to raise awareness among the target audience. - #### Post-Launch + - **Task 5.1:** Monitor the tool's usage and performance, addressing any issues or bugs that arise post-launch. - **Task 5.2:** Continuously update the AI model and feature based on new user feedback and technological advancements in AI and IDE development. -This roadmap provides a structured approach to developing the `RenameVariablesAction` feature, from initial setup to post-launch support, ensuring a high-quality tool that meets the needs of its users. +This roadmap provides a structured approach to developing the `RenameVariablesAction` feature, from initial setup to post-launch support, ensuring a +high-quality tool that meets the needs of its users. # kotlin\com\github\simiacryptus\aicoder\actions\dev\PrintTreeAction.kt - #### Feature Development Roadmap for PrintTreeAction -The development roadmap for the `PrintTreeAction` feature, an IntelliJ action designed to print the tree structure of a PsiFile, is outlined below. This roadmap is structured to ensure a systematic and efficient development process, from initial planning to final release and future enhancements. - +The development roadmap for the `PrintTreeAction` feature, an IntelliJ action designed to print the tree structure of a PsiFile, is outlined below. This roadmap +is structured to ensure a systematic and efficient development process, from initial planning to final release and future enhancements. ##### Phase 1: Planning and Design -- **Requirement Analysis**: Identify and document the specific requirements for the `PrintTreeAction` feature, including the need to print the tree structure of PsiFiles for development and debugging purposes. -- **Feasibility Study**: Assess the technical feasibility of the feature, including integration with IntelliJ's action system and PsiFile structure analysis capabilities. -- **Design Specification**: Create a detailed design document outlining the architecture of the `PrintTreeAction`, including its interaction with the IntelliJ platform and the PsiUtil utility class. +- **Requirement Analysis**: Identify and document the specific requirements for the `PrintTreeAction` feature, including the need to print the tree structure of + PsiFiles for development and debugging purposes. +- **Feasibility Study**: Assess the technical feasibility of the feature, including integration with IntelliJ's action system and PsiFile structure analysis + capabilities. +- **Design Specification**: Create a detailed design document outlining the architecture of the `PrintTreeAction`, including its interaction with the IntelliJ + platform and the PsiUtil utility class. ##### Phase 2: Development + - **Environment Setup**: Prepare the development environment, including setting up IntelliJ SDK and necessary plugins for development. - **Core Implementation**: - Implement the `PrintTreeAction` class, extending the `BaseAction` class to integrate with IntelliJ's action system. @@ -671,20 +826,21 @@ The development roadmap for the `PrintTreeAction` feature, an IntelliJ action de - Implement the `isEnabled` method to ensure the action is available only when the `devActions` setting is enabled. - **Logging Integration**: Integrate with SLF4J for logging the tree structure output to facilitate debugging and verification. - ##### Phase 3: Testing + - **Unit Testing**: Develop unit tests for the `PrintTreeAction` class to ensure the functionality works as expected under various scenarios. -- **Integration Testing**: Perform integration testing to verify the action's compatibility with the IntelliJ platform and its ability to accurately print PsiFile tree structures. +- **Integration Testing**: Perform integration testing to verify the action's compatibility with the IntelliJ platform and its ability to accurately print + PsiFile tree structures. - **User Acceptance Testing (UAT)**: Conduct UAT with a select group of developers to gather feedback on the usability and effectiveness of the feature. - ##### Phase 4: Deployment + - **Documentation**: Create comprehensive documentation, including usage instructions and troubleshooting tips. - **Release Preparation**: Package the `PrintTreeAction` feature as part of the plugin and perform final pre-release testing. - **Launch**: Release the updated plugin version to the JetBrains Marketplace, making the `PrintTreeAction` feature available to all users. - ##### Phase 5: Maintenance and Future Enhancements + - **Monitoring and Support**: Monitor the feature's performance and provide support for any issues encountered by users. - **Feedback Collection**: Collect user feedback to identify potential areas for improvement. - **Future Enhancements**: @@ -692,231 +848,293 @@ The development roadmap for the `PrintTreeAction` feature, an IntelliJ action de - Implement customizable tree structure output formats. - Integrate with other development tools and services for advanced tree analysis and visualization. -This roadmap provides a structured approach to developing the `PrintTreeAction` feature, ensuring it meets the needs of developers while maintaining high standards of quality and usability. +This roadmap provides a structured approach to developing the `PrintTreeAction` feature, ensuring it meets the needs of developers while maintaining high +standards of quality and usability. # kotlin\com\github\simiacryptus\aicoder\actions\FileContextAction.kt -Creating a feature development roadmap for the `FileContextAction` class and its associated functionalities involves outlining the planned enhancements, new features, and improvements. This roadmap will guide the development process, ensuring that the project evolves in a structured and efficient manner. Here's a proposed roadmap based on the existing codebase: - +Creating a feature development roadmap for the `FileContextAction` class and its associated functionalities involves outlining the planned enhancements, new +features, and improvements. This roadmap will guide the development process, ensuring that the project evolves in a structured and efficient manner. Here's a +proposed roadmap based on the existing codebase: #### Phase 1: Foundation and Stability -- **Refactor and Code Cleanup**: Begin by refactoring the existing code for clarity and maintainability. This includes simplifying complex methods, improving naming conventions, and removing redundant code. -- **Enhanced Error Handling**: Improve error handling mechanisms to ensure the system is robust against failures. This involves adding more try-catch blocks where necessary and providing meaningful error messages to users. -- **Unit Testing**: Develop a comprehensive suite of unit tests to cover critical functionalities. This will help in identifying bugs early in the development process and ensure that changes do not break existing features. +- **Refactor and Code Cleanup**: Begin by refactoring the existing code for clarity and maintainability. This includes simplifying complex methods, improving + naming conventions, and removing redundant code. +- **Enhanced Error Handling**: Improve error handling mechanisms to ensure the system is robust against failures. This involves adding more try-catch blocks + where necessary and providing meaningful error messages to users. +- **Unit Testing**: Develop a comprehensive suite of unit tests to cover critical functionalities. This will help in identifying bugs early in the development + process and ensure that changes do not break existing features. #### Phase 2: Feature Enhancement -- **Configurability**: Enhance the `getConfig` method to support more complex and dynamic configurations. This could involve integrating with external configuration sources or supporting environment-specific configurations. -- **Support for Additional File Types**: Extend the `supportsFiles` and `supportsFolders` flags to include more granular control over which file types and folder structures can be processed by the action. -- **Performance Optimization**: Optimize the performance of file and folder processing, especially for large projects. This could involve parallel processing, caching, or other techniques to reduce processing time. +- **Configurability**: Enhance the `getConfig` method to support more complex and dynamic configurations. This could involve integrating with external + configuration sources or supporting environment-specific configurations. +- **Support for Additional File Types**: Extend the `supportsFiles` and `supportsFolders` flags to include more granular control over which file types and + folder structures can be processed by the action. +- **Performance Optimization**: Optimize the performance of file and folder processing, especially for large projects. This could involve parallel processing, + caching, or other techniques to reduce processing time. #### Phase 3: User Experience and Integration -- **UI Improvements**: Enhance the user interface components used in the action, making them more intuitive and responsive. This could involve adding progress indicators, confirmation dialogs, and customizable settings. -- **Integration with Other Tools**: Explore integration possibilities with other tools and plugins within the IntelliJ ecosystem to provide a seamless experience for users. This could involve supporting file synchronization with external systems or integrating with version control systems. -- **Documentation and Tutorials**: Create comprehensive documentation and tutorials for users and developers. This should include detailed usage instructions, configuration guides, and examples of extending the action for custom use cases. +- **UI Improvements**: Enhance the user interface components used in the action, making them more intuitive and responsive. This could involve adding progress + indicators, confirmation dialogs, and customizable settings. +- **Integration with Other Tools**: Explore integration possibilities with other tools and plugins within the IntelliJ ecosystem to provide a seamless + experience for users. This could involve supporting file synchronization with external systems or integrating with version control systems. +- **Documentation and Tutorials**: Create comprehensive documentation and tutorials for users and developers. This should include detailed usage instructions, + configuration guides, and examples of extending the action for custom use cases. #### Phase 4: Advanced Features and Community Feedback -- **Advanced File Manipulation**: Introduce advanced file manipulation features such as batch processing, file transformations, and automated refactoring based on user-defined rules. -- **Feedback Loop**: Establish a mechanism for collecting user feedback and feature requests. This could involve integrating with issue tracking systems or creating a community forum. -- **Plugin Ecosystem**: Encourage the development of plugins or extensions that add new functionalities or integrate with other services. Provide documentation and support for developers looking to extend the action. +- **Advanced File Manipulation**: Introduce advanced file manipulation features such as batch processing, file transformations, and automated refactoring based + on user-defined rules. +- **Feedback Loop**: Establish a mechanism for collecting user feedback and feature requests. This could involve integrating with issue tracking systems or + creating a community forum. +- **Plugin Ecosystem**: Encourage the development of plugins or extensions that add new functionalities or integrate with other services. Provide documentation + and support for developers looking to extend the action. #### Phase 5: Maintenance and Continuous Improvement -- **Regular Updates**: Commit to regular updates to the action, including bug fixes, performance improvements, and compatibility updates for new versions of IntelliJ. -- **Community Engagement**: Engage with the user and developer community through forums, social media, and conferences. Use these platforms to gather feedback, share updates, and promote the action. -- **Long-term Support**: Provide long-term support for the action, ensuring that it remains compatible with future versions of IntelliJ and continues to meet users' needs. + +- **Regular Updates**: Commit to regular updates to the action, including bug fixes, performance improvements, and compatibility updates for new versions of + IntelliJ. +- **Community Engagement**: Engage with the user and developer community through forums, social media, and conferences. Use these platforms to gather feedback, + share updates, and promote the action. +- **Long-term Support**: Provide long-term support for the action, ensuring that it remains compatible with future versions of IntelliJ and continues to meet + users' needs. This roadmap is a living document and should be revisited regularly to incorporate new ideas, technologies, and feedback from users and contributors. # kotlin\com\github\simiacryptus\aicoder\actions\generic\CodeChatAction.kt -Creating a feature development roadmap for the `CodeChatAction` class involves outlining the future enhancements, improvements, and additions that could be made to enrich its functionality, usability, and integration capabilities. This roadmap will be divided into short-term, mid-term, and long-term goals, considering the current state of the class as a starting point. - +Creating a feature development roadmap for the `CodeChatAction` class involves outlining the future enhancements, improvements, and additions that could be made +to enrich its functionality, usability, and integration capabilities. This roadmap will be divided into short-term, mid-term, and long-term goals, considering +the current state of the class as a starting point. #### Short-Term Goals (1-3 Months) 1. **Enhanced Error Handling and Logging**: - - Improve error handling to provide more descriptive messages for failures, especially for network and file access errors. - - Enhance logging to include more detailed information for debugging purposes, such as session initiation and termination logs. + +- Improve error handling to provide more descriptive messages for failures, especially for network and file access errors. +- Enhance logging to include more detailed information for debugging purposes, such as session initiation and termination logs. 2. **User Interface Improvements**: - - Develop a more intuitive and user-friendly interface for the code chat feature, making it easier for users to start a chat session. - - Implement visual indicators for the chat session's status (active, waiting, closed). + +- Develop a more intuitive and user-friendly interface for the code chat feature, making it easier for users to start a chat session. +- Implement visual indicators for the chat session's status (active, waiting, closed). 3. **Performance Optimization**: - - Optimize the initialization of the chat server and the handling of chat sessions to reduce latency. - - Investigate and reduce memory footprint for each chat session to support more concurrent users. +- Optimize the initialization of the chat server and the handling of chat sessions to reduce latency. +- Investigate and reduce memory footprint for each chat session to support more concurrent users. #### Mid-Term Goals (4-6 Months) 1. **Integration with Other IDEs**: - - Extend the functionality to be compatible with other popular IDEs beyond IntelliJ, such as Eclipse and VS Code. - - Develop plugins or extensions for these IDEs to facilitate easy access to the code chat feature. + +- Extend the functionality to be compatible with other popular IDEs beyond IntelliJ, such as Eclipse and VS Code. +- Develop plugins or extensions for these IDEs to facilitate easy access to the code chat feature. 2. **Support for More Programming Languages**: - - Increase the number of supported programming languages in the `ComputerLanguage` class to cater to a broader audience. - - Implement language-specific features in the chat, such as syntax highlighting and code suggestions. + +- Increase the number of supported programming languages in the `ComputerLanguage` class to cater to a broader audience. +- Implement language-specific features in the chat, such as syntax highlighting and code suggestions. 3. **Session Management Enhancements**: - - Introduce features for managing chat sessions, such as the ability to save, archive, and revisit past chat sessions. - - Implement user authentication and session privacy controls to enhance security. +- Introduce features for managing chat sessions, such as the ability to save, archive, and revisit past chat sessions. +- Implement user authentication and session privacy controls to enhance security. #### Long-Term Goals (7-12 Months) 1. **AI-Powered Code Assistance**: - - Integrate AI-based code analysis and suggestion tools to provide real-time assistance during code chat sessions. - - Explore the use of machine learning models for code completion, bug detection, and optimization suggestions. + +- Integrate AI-based code analysis and suggestion tools to provide real-time assistance during code chat sessions. +- Explore the use of machine learning models for code completion, bug detection, and optimization suggestions. 2. **Collaborative Coding Features**: - - Develop features that allow multiple users to join a code chat session and collaboratively edit code in real-time. - - Implement version control integration to manage changes made during collaborative sessions. + +- Develop features that allow multiple users to join a code chat session and collaboratively edit code in real-time. +- Implement version control integration to manage changes made during collaborative sessions. 3. **Extensibility and API Development**: - - Design and expose APIs that allow third-party developers to create add-ons or integrate the code chat feature into their tools. - - Encourage community contributions by documenting the API and providing development guides. + +- Design and expose APIs that allow third-party developers to create add-ons or integrate the code chat feature into their tools. +- Encourage community contributions by documenting the API and providing development guides. 4. **Comprehensive Analytics and Reporting**: - - Implement analytics to track usage patterns, popular languages, and other metrics to inform future development. - - Provide users with reports on their chat sessions, including summaries, code changes, and recommendations for improvement. -This roadmap aims to guide the development of the `CodeChatAction` class and its associated features, ensuring continuous improvement and adaptation to user needs and technological advancements. +- Implement analytics to track usage patterns, popular languages, and other metrics to inform future development. +- Provide users with reports on their chat sessions, including summaries, code changes, and recommendations for improvement. -# kotlin\com\github\simiacryptus\aicoder\actions\generic\GenerateRelatedFileAction.kt +This roadmap aims to guide the development of the `CodeChatAction` class and its associated features, ensuring continuous improvement and adaptation to user +needs and technological advancements. -The code provided is part of a larger project aimed at integrating AI-driven functionalities into an IDE, specifically for generating analogue files based on directives. The roadmap for developing and enhancing this feature can be structured into several key phases, each focusing on different aspects of the project, from foundational setup to advanced features and optimizations. Below is a proposed feature development roadmap: +# kotlin\com\github\simiacryptus\aicoder\actions\generic\GenerateRelatedFileAction.kt +The code provided is part of a larger project aimed at integrating AI-driven functionalities into an IDE, specifically for generating analogue files based on +directives. The roadmap for developing and enhancing this feature can be structured into several key phases, each focusing on different aspects of the project, +from foundational setup to advanced features and optimizations. Below is a proposed feature development roadmap: #### Phase 1: Foundation and Setup + - **Project Setup:** Establish the project structure, including necessary libraries and dependencies. - **Basic UI Integration:** Develop a simple UI for inputting directives and displaying results within the IDE. - **File Handling:** Implement basic file operations such as reading from and writing to files within the project context. - #### Phase 2: Core Functionality + - **Directive Processing:** Enhance the system to process natural language directives more effectively, possibly incorporating more advanced NLP techniques. -- **AI Integration:** Integrate the AI model for generating code based on directives, ensuring it can handle a variety of inputs and generate relevant code snippets. +- **AI Integration:** Integrate the AI model for generating code based on directives, ensuring it can handle a variety of inputs and generate relevant code + snippets. - **Feedback Loop:** Implement a mechanism for users to provide feedback on the generated code, which can be used to improve the AI model. - #### Phase 3: Usability Enhancements + - **Advanced UI Features:** Develop a more sophisticated UI, possibly including features like directive history, favorite directives, and template management. - **Directive Suggestions:** Implement a feature to suggest directives based on the project context or previously successful directives. -- **Error Handling and Validation:** Enhance error handling to provide more informative feedback to the user, and implement validation checks for generated code. - +- **Error Handling and Validation:** Enhance error handling to provide more informative feedback to the user, and implement validation checks for generated + code. #### Phase 4: Collaboration and Sharing -- **Sharing Mechanism:** Develop a feature allowing users to share their directives and the resulting code with others, fostering a community of practice. -- **Collaborative Editing:** Explore the possibility of integrating collaborative editing features, allowing multiple users to work on the same directive or code snippet simultaneously. +- **Sharing Mechanism:** Develop a feature allowing users to share their directives and the resulting code with others, fostering a community of practice. +- **Collaborative Editing:** Explore the possibility of integrating collaborative editing features, allowing multiple users to work on the same directive or + code snippet simultaneously. #### Phase 5: Advanced Features and Optimizations + - **Performance Optimization:** Optimize the performance of the system, ensuring it can handle large projects and complex directives efficiently. - **Custom AI Models:** Allow users to train custom AI models based on their coding style or project-specific needs. - **Integration with Other Tools:** Explore integrations with other development tools and services, enhancing the overall development workflow. - #### Phase 6: Security and Privacy -- **Security Measures:** Implement robust security measures to protect user data and code. -- **Privacy Controls:** Provide users with clear privacy controls, ensuring they understand how their data is used and allowing them to opt-out of data collection if desired. +- **Security Measures:** Implement robust security measures to protect user data and code. +- **Privacy Controls:** Provide users with clear privacy controls, ensuring they understand how their data is used and allowing them to opt-out of data + collection if desired. #### Phase 7: Feedback and Iteration + - **User Feedback Collection:** Establish mechanisms for collecting user feedback on a continuous basis. -- **Iterative Improvement:** Use the collected feedback to iteratively improve the system, focusing on both fixing issues and introducing new features based on user demand. +- **Iterative Improvement:** Use the collected feedback to iteratively improve the system, focusing on both fixing issues and introducing new features based on + user demand. This roadmap is designed to be flexible, allowing for adjustments based on user feedback, technological advancements, and changes in project priorities. # kotlin\com\github\simiacryptus\aicoder\actions\generic\AppendTextWithChatAction.kt -Creating a feature development roadmap for the `AppendTextWithChatAction` class within the context of enhancing an IDE plugin for AI-assisted coding involves outlining a series of steps or phases. This roadmap aims to guide the development, from initial enhancements to more sophisticated features, ensuring the plugin remains useful, efficient, and user-friendly. Here's a proposed roadmap: - +Creating a feature development roadmap for the `AppendTextWithChatAction` class within the context of enhancing an IDE plugin for AI-assisted coding involves +outlining a series of steps or phases. This roadmap aims to guide the development, from initial enhancements to more sophisticated features, ensuring the plugin +remains useful, efficient, and user-friendly. Here's a proposed roadmap: #### Phase 1: Initial Enhancements and Fixes + - **Bug Fixes:** Address any known bugs in the `AppendTextWithChatAction` class to ensure stability. - **Performance Optimization:** Improve the response time of the AI model by optimizing the API call and handling of the response. -- **User Interface Improvements:** Enhance the user experience by providing clear feedback when the action is triggered, such as a loading indicator or a success message. - +- **User Interface Improvements:** Enhance the user experience by providing clear feedback when the action is triggered, such as a loading indicator or a + success message. #### Phase 2: Configuration and Customization -- **Model Configuration:** Allow users to select and configure the AI model directly from the plugin settings, including the ability to change the model, temperature, and other parameters. + +- **Model Configuration:** Allow users to select and configure the AI model directly from the plugin settings, including the ability to change the model, + temperature, and other parameters. - **Custom Prompts:** Enable users to define custom prompts that will be used instead of the default "Append text to the end of the user's prompt". - **Context Awareness:** Improve the action to better understand the context of the selected text, possibly by analyzing the surrounding code or comments. - #### Phase 3: Advanced Features -- **Multi-Language Support:** Extend the functionality to support multiple programming languages, adapting the action based on the language of the current file. -- **Interactive Mode:** Implement an interactive mode where users can iteratively refine the appended text with the help of the AI, providing feedback or corrections. -- **Version Control Integration:** Integrate with version control systems to allow users to easily commit changes made by the `AppendTextWithChatAction`, including automatic commit messages generated by the AI. +- **Multi-Language Support:** Extend the functionality to support multiple programming languages, adapting the action based on the language of the current file. +- **Interactive Mode:** Implement an interactive mode where users can iteratively refine the appended text with the help of the AI, providing feedback or + corrections. +- **Version Control Integration:** Integrate with version control systems to allow users to easily commit changes made by the `AppendTextWithChatAction`, + including automatic commit messages generated by the AI. #### Phase 4: Collaboration and Sharing + - **Shared Configurations:** Allow users to share their custom configurations and prompts with the community, fostering a collaborative environment. - **Usage Analytics:** Collect anonymized data on how the action is used to identify popular features and areas for improvement. - **Feedback Mechanism:** Implement a direct feedback mechanism within the plugin, allowing users to report issues or suggest features. - #### Phase 5: Scalability and Security + - **Enterprise Features:** Add features tailored for enterprise users, such as support for private AI models or enhanced security measures for API interactions. - **Scalability Improvements:** Ensure the plugin can handle a large number of requests efficiently, possibly by implementing request queuing or load balancing. -- **Security Audits:** Regularly conduct security audits to identify and mitigate potential vulnerabilities, especially those related to data privacy and API interactions. - +- **Security Audits:** Regularly conduct security audits to identify and mitigate potential vulnerabilities, especially those related to data privacy and API + interactions. #### Phase 6: Future Directions -- **AI-Assisted Code Review:** Explore the possibility of extending the plugin to provide AI-assisted code reviews, offering suggestions for improvement or identifying potential issues. + +- **AI-Assisted Code Review:** Explore the possibility of extending the plugin to provide AI-assisted code reviews, offering suggestions for improvement or + identifying potential issues. - **Integration with Other Tools:** Look into integrating the plugin with other development tools and platforms, enhancing its utility and accessibility. - **Adaptive Learning:** Implement machine learning techniques to allow the plugin to learn from user interactions and improve its suggestions over time. -This roadmap provides a structured approach to developing the `AppendTextWithChatAction` class and related features, ensuring continuous improvement and adaptation to user needs. +This roadmap provides a structured approach to developing the `AppendTextWithChatAction` class and related features, ensuring continuous improvement and +adaptation to user needs. # kotlin\com\github\simiacryptus\aicoder\actions\generic\CreateFileFromDescriptionAction.kt -The `CreateFileFromDescriptionAction` class is part of a larger project aimed at automating file creation within a software development environment. This class specifically focuses on generating files based on natural language directives, leveraging an AI model to interpret these directives and create appropriate file content and paths. Below is a proposed feature development roadmap to enhance the capabilities and performance of the `CreateFileFromDescriptionAction` class. - +The `CreateFileFromDescriptionAction` class is part of a larger project aimed at automating file creation within a software development environment. This class +specifically focuses on generating files based on natural language directives, leveraging an AI model to interpret these directives and create appropriate file +content and paths. Below is a proposed feature development roadmap to enhance the capabilities and performance of the `CreateFileFromDescriptionAction` class. #### Phase 1: Core Functionality Improvement -- **Refine AI Interpretation**: Improve the AI's ability to understand more complex directives by training with a diverse set of instructions and file types. -- **Enhance File Path Generation**: Develop a more sophisticated algorithm for generating file paths, ensuring they are logical and adhere to project structure conventions. -- **Support Multiple File Types**: Extend the class to support the creation of various file types (e.g., `.java`, `.xml`, `.properties`) based on the directive content. +- **Refine AI Interpretation**: Improve the AI's ability to understand more complex directives by training with a diverse set of instructions and file types. +- **Enhance File Path Generation**: Develop a more sophisticated algorithm for generating file paths, ensuring they are logical and adhere to project structure + conventions. +- **Support Multiple File Types**: Extend the class to support the creation of various file types (e.g., `.java`, `.xml`, `.properties`) based on the directive + content. #### Phase 2: User Experience and Usability + - **Interactive Directive Input**: Implement a GUI or CLI interface that allows users to input directives interactively and receive immediate feedback. -- **Preview Generated File**: Before finalizing the file creation, provide users with a preview of the generated file path and content for confirmation or further modification. +- **Preview Generated File**: Before finalizing the file creation, provide users with a preview of the generated file path and content for confirmation or + further modification. - **Settings Customization**: Allow users to customize settings such as default file headers, footers, and templates for different file types. - #### Phase 3: Integration and Compatibility -- **IDE Integration**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code to seamlessly use this functionality within the development workflow. -- **Version Control System Compatibility**: Ensure that generated files are compatible with version control systems (e.g., Git) by automatically adding them to the repository and providing options for commit messages. +- **IDE Integration**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code to seamlessly + use this functionality within the development workflow. +- **Version Control System Compatibility**: Ensure that generated files are compatible with version control systems (e.g., Git) by automatically adding them to + the repository and providing options for commit messages. #### Phase 4: Advanced Features -- **Batch File Creation**: Enable the creation of multiple files from a single directive, useful for setting up new modules or features that require a standard set of files. -- **Directive Templates**: Introduce directive templates for common development tasks (e.g., creating a REST controller, setting up a logging configuration) to streamline the file creation process. -- **AI Feedback Loop**: Implement a feedback mechanism where users can rate the accuracy and usefulness of the generated files, which is then used to further train and refine the AI model. +- **Batch File Creation**: Enable the creation of multiple files from a single directive, useful for setting up new modules or features that require a standard + set of files. +- **Directive Templates**: Introduce directive templates for common development tasks (e.g., creating a REST controller, setting up a logging configuration) to + streamline the file creation process. +- **AI Feedback Loop**: Implement a feedback mechanism where users can rate the accuracy and usefulness of the generated files, which is then used to further + train and refine the AI model. #### Phase 5: Performance and Scalability -- **Optimize AI Model Performance**: Continuously monitor and optimize the performance of the AI model to handle larger directives and projects without significant delays. -- **Scalability Enhancements**: Ensure the system can scale to support large teams and projects, including efficient handling of concurrent file creation requests. +- **Optimize AI Model Performance**: Continuously monitor and optimize the performance of the AI model to handle larger directives and projects without + significant delays. +- **Scalability Enhancements**: Ensure the system can scale to support large teams and projects, including efficient handling of concurrent file creation + requests. #### Phase 6: Security and Compliance -- **Security Audits**: Regularly conduct security audits to identify and mitigate potential vulnerabilities, especially those related to handling and storing project files. -- **Compliance Checks**: Integrate compliance checks to ensure that generated files adhere to industry standards and regulations relevant to the project's domain. -This roadmap outlines a comprehensive approach to developing the `CreateFileFromDescriptionAction` class into a robust tool that enhances productivity and streamlines the file creation process in software development projects. Each phase builds upon the previous one, gradually introducing new features and improvements based on user feedback and technological advancements. +- **Security Audits**: Regularly conduct security audits to identify and mitigate potential vulnerabilities, especially those related to handling and storing + project files. +- **Compliance Checks**: Integrate compliance checks to ensure that generated files adhere to industry standards and regulations relevant to the project's + domain. -# kotlin\com\github\simiacryptus\aicoder\actions\dev\InternalCoderAction.kt +This roadmap outlines a comprehensive approach to developing the `CreateFileFromDescriptionAction` class into a robust tool that enhances productivity and +streamlines the file creation process in software development projects. Each phase builds upon the previous one, gradually introducing new features and +improvements based on user feedback and technological advancements. -The `InternalCoderAction` class is part of a larger project aimed at integrating coding assistance tools directly into the IntelliJ IDE. This class specifically handles the initiation and management of a coding session that leverages an AI coding agent. Below is a proposed feature development roadmap to enhance the capabilities and user experience of this integration. +# kotlin\com\github\simiacryptus\aicoder\actions\dev\InternalCoderAction.kt +The `InternalCoderAction` class is part of a larger project aimed at integrating coding assistance tools directly into the IntelliJ IDE. This class specifically +handles the initiation and management of a coding session that leverages an AI coding agent. Below is a proposed feature development roadmap to enhance the +capabilities and user experience of this integration. #### Phase 1: Core Functionality and Stability + - **1.1 Initial Setup and Integration** - Complete the integration of the `InternalCoderAction` class with IntelliJ IDE. - Ensure the action is correctly triggered from the IDE interface. @@ -929,8 +1147,8 @@ The `InternalCoderAction` class is part of a larger project aimed at integrating - Develop a more intuitive and responsive UI for the coding agent within the IDE. - Implement syntax highlighting and real-time feedback for the coding session. - #### Phase 2: Advanced Features and Customization + - **2.1 Custom AI Models** - Allow users to select different AI models based on their coding preferences or project requirements. - Implement a mechanism for users to train custom models with their codebases. @@ -943,8 +1161,8 @@ The `InternalCoderAction` class is part of a larger project aimed at integrating - Develop a settings panel for users to customize the behavior of the coding agent (e.g., response verbosity, suggestion frequency). - Allow users to set project-specific preferences for the coding agent. - #### Phase 3: Collaboration and Sharing + - **3.1 Collaborative Coding Sessions** - Implement functionality for multiple users to join and collaborate within the same coding session. - Add chat and communication tools to facilitate collaboration among users. @@ -957,8 +1175,8 @@ The `InternalCoderAction` class is part of a larger project aimed at integrating - Develop features for directly committing code from the coding session to version control systems (e.g., Git). - Implement a history and changes review system within the coding session interface. - #### Phase 4: Analytics and Feedback + - **4.1 Session Analytics** - Implement analytics features to provide users with insights into their coding habits, most used features, and potential areas for improvement. - Allow users to track their progress over time and set coding goals. @@ -971,20 +1189,23 @@ The `InternalCoderAction` class is part of a larger project aimed at integrating - Create comprehensive documentation for the coding agent, including tutorials, FAQs, and troubleshooting guides. - Establish a support system for users to get help with issues or questions. -This roadmap outlines a comprehensive plan for developing and enhancing the `InternalCoderAction` class and its associated features. Each phase builds upon the previous one, gradually introducing more advanced capabilities and improving the user experience. +This roadmap outlines a comprehensive plan for developing and enhancing the `InternalCoderAction` class and its associated features. Each phase builds upon the +previous one, gradually introducing more advanced capabilities and improving the user experience. # kotlin\com\github\simiacryptus\aicoder\actions\generic\RedoLast.kt -Developing a feature, especially for a software project like an IntelliJ plugin, requires careful planning and execution. Below is a feature development roadmap for enhancing the "RedoLast" action, which allows users to redo the last AI Coder action they performed in the editor. This roadmap outlines the steps from initial planning to release and future improvements. - +Developing a feature, especially for a software project like an IntelliJ plugin, requires careful planning and execution. Below is a feature development roadmap +for enhancing the "RedoLast" action, which allows users to redo the last AI Coder action they performed in the editor. This roadmap outlines the steps from +initial planning to release and future improvements. #### Phase 1: Planning and Research + - **Requirement Gathering**: Collect feedback from users about the current "RedoLast" feature, focusing on limitations and desired improvements. - **Feasibility Study**: Assess the technical feasibility of proposed enhancements, including API limitations and compatibility issues. - **Design Specification**: Create a detailed design document outlining the proposed architecture, UI changes, and interaction with IntelliJ's API. - #### Phase 2: Development + - **Environment Setup**: Ensure the development environment is configured with all necessary dependencies and SDKs. - **Core Functionality Enhancement**: - Improve the undo/redo stack management to handle more complex scenarios or multiple redo levels. @@ -993,673 +1214,867 @@ Developing a feature, especially for a software project like an IntelliJ plugin, - Add visual indicators or notifications to inform users when a redo action is available or has been performed. - Enhance the context menu with icons or additional options related to redo actions. - #### Phase 3: Testing + - **Unit Testing**: Develop unit tests covering new logic and modifications to ensure stability and prevent regressions. - **Integration Testing**: Test the integration with IntelliJ IDEA, focusing on compatibility across different versions and operating systems. - **User Acceptance Testing (UAT)**: Release a beta version to a select group of users for feedback on usability and functionality. - #### Phase 4: Documentation and Release + - **Documentation**: Update the user guide and online documentation to reflect new features and changes. Include screenshots and examples for clarity. - **Release Preparation**: Finalize the release notes, highlighting new features, improvements, and known issues. - **Launch**: Release the updated "RedoLast" action to the JetBrains Marketplace and notify users through newsletters and social media. - #### Phase 5: Post-Release Support and Future Enhancements + - **Monitoring and Support**: Monitor user feedback and bug reports. Provide timely updates to address any issues. - **Performance Optimization**: Analyze usage patterns to identify performance bottlenecks and optimize accordingly. -- **Feature Expansion**: Based on user feedback, consider adding more sophisticated redo capabilities, such as redoing actions from a history list or integrating with version control systems for more granular undo/redo operations. - +- **Feature Expansion**: Based on user feedback, consider adding more sophisticated redo capabilities, such as redoing actions from a history list or + integrating with version control systems for more granular undo/redo operations. #### Conclusion -This roadmap provides a structured approach to enhancing the "RedoLast" action, focusing on user needs, technical excellence, and continuous improvement. By following these phases, the development team can ensure a successful feature enhancement that meets or exceeds user expectations. -# kotlin\com\github\simiacryptus\aicoder\actions\generic\GenerateDocumentationAction.kt +This roadmap provides a structured approach to enhancing the "RedoLast" action, focusing on user needs, technical excellence, and continuous improvement. By +following these phases, the development team can ensure a successful feature enhancement that meets or exceeds user expectations. +# kotlin\com\github\simiacryptus\aicoder\actions\generic\GenerateDocumentationAction.kt #### Feature Development Roadmap for GenerateDocumentationAction -The `GenerateDocumentationAction` class is a sophisticated component designed to automate the process of compiling documentation from code files within a project. This roadmap outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. - +The `GenerateDocumentationAction` class is a sophisticated component designed to automate the process of compiling documentation from code files within a +project. This roadmap outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. ##### Phase 1: Core Functionality Enhancements 1. **Improved Content Transformation** - - Implement advanced natural language processing (NLP) techniques to improve the quality of the generated documentation. - - Support for multiple languages and code comments to cater to a diverse developer base. + +- Implement advanced natural language processing (NLP) techniques to improve the quality of the generated documentation. +- Support for multiple languages and code comments to cater to a diverse developer base. 2. **User Interface Improvements** - - Develop a more intuitive and user-friendly settings dialog. - - Implement real-time previews of the transformation message and the resulting documentation. + +- Develop a more intuitive and user-friendly settings dialog. +- Implement real-time previews of the transformation message and the resulting documentation. 3. **Performance Optimization** - - Optimize the file processing and content transformation pipeline for faster execution. - - Implement asynchronous processing to prevent UI freezing during documentation compilation. +- Optimize the file processing and content transformation pipeline for faster execution. +- Implement asynchronous processing to prevent UI freezing during documentation compilation. ##### Phase 2: Integration and Compatibility 1. **Version Control System Integration** - - Integrate with popular version control systems (e.g., Git) to automatically document changes in code. - - Support for generating documentation pull requests based on the compiled documentation. + +- Integrate with popular version control systems (e.g., Git) to automatically document changes in code. +- Support for generating documentation pull requests based on the compiled documentation. 2. **Support for Additional File Types** - - Extend the functionality to support more file types beyond the current scope, including but not limited to XML, JSON, and YAML. - - Implement customizable parsers for different file types to improve the flexibility of the tool. + +- Extend the functionality to support more file types beyond the current scope, including but not limited to XML, JSON, and YAML. +- Implement customizable parsers for different file types to improve the flexibility of the tool. 3. **IDE Compatibility** - - Ensure compatibility with other JetBrains IDEs (e.g., PyCharm, WebStorm) to cater to a broader audience. - - Explore the possibility of porting the tool to other development environments (e.g., Visual Studio Code). +- Ensure compatibility with other JetBrains IDEs (e.g., PyCharm, WebStorm) to cater to a broader audience. +- Explore the possibility of porting the tool to other development environments (e.g., Visual Studio Code). ##### Phase 3: Advanced Features 1. **Documentation Versioning** - - Implement a versioning system for the generated documentation to track changes over time. - - Support for tagging and branching in the documentation, mirroring the version control system's functionality. + +- Implement a versioning system for the generated documentation to track changes over time. +- Support for tagging and branching in the documentation, mirroring the version control system's functionality. 2. **Collaborative Editing** - - Introduce features for collaborative editing and review of the generated documentation. - - Implement commenting and suggestion systems within the documentation compilation interface. + +- Introduce features for collaborative editing and review of the generated documentation. +- Implement commenting and suggestion systems within the documentation compilation interface. 3. **Customizable Templates** - - Allow users to create and use customizable templates for the generated documentation to match their project's style guide. - - Support for importing and exporting templates to share with the community. +- Allow users to create and use customizable templates for the generated documentation to match their project's style guide. +- Support for importing and exporting templates to share with the community. ##### Phase 4: Community and Ecosystem 1. **Plugin Marketplace** - - Develop a marketplace for users to share and discover custom templates, parsers, and other extensions. - - Implement a rating and review system to help users find the best resources. + +- Develop a marketplace for users to share and discover custom templates, parsers, and other extensions. +- Implement a rating and review system to help users find the best resources. 2. **Documentation Hosting and Sharing** - - Provide options for hosting the compiled documentation on popular platforms (e.g., GitHub Pages, Read the Docs). - - Implement easy sharing options to distribute the documentation to stakeholders. + +- Provide options for hosting the compiled documentation on popular platforms (e.g., GitHub Pages, Read the Docs). +- Implement easy sharing options to distribute the documentation to stakeholders. 3. **Educational Resources** - - Create comprehensive tutorials, guides, and video content to help users get the most out of the tool. - - Establish a community forum for users to share tips, ask questions, and provide feedback. +- Create comprehensive tutorials, guides, and video content to help users get the most out of the tool. +- Establish a community forum for users to share tips, ask questions, and provide feedback. ##### Conclusion -The development roadmap for `GenerateDocumentationAction` aims to create a powerful, user-friendly tool that simplifies the documentation process for developers. By focusing on core functionality enhancements, integration and compatibility, advanced features, and building a supportive community, the tool will become an indispensable part of the software development lifecycle. +The development roadmap for `GenerateDocumentationAction` aims to create a powerful, user-friendly tool that simplifies the documentation process for +developers. By focusing on core functionality enhancements, integration and compatibility, advanced features, and building a supportive community, the tool will +become an indispensable part of the software development lifecycle. # kotlin\com\github\simiacryptus\aicoder\actions\generic\VoiceToTextAction.kt -The `VoiceToTextAction` class is a sophisticated piece of software designed to integrate speech-to-text capabilities within an IDE, leveraging audio recording and processing to convert spoken words into text. This feature can significantly enhance productivity by allowing developers to dictate code comments, documentation, or even code itself. Below is a proposed feature development roadmap to enhance and expand the capabilities of the `VoiceToTextAction` class. - +The `VoiceToTextAction` class is a sophisticated piece of software designed to integrate speech-to-text capabilities within an IDE, leveraging audio recording +and processing to convert spoken words into text. This feature can significantly enhance productivity by allowing developers to dictate code comments, +documentation, or even code itself. Below is a proposed feature development roadmap to enhance and expand the capabilities of the `VoiceToTextAction` class. #### Phase 1: Core Functionality and Stability + - **1.1 Initial Release**: Ensure the core functionality of audio recording, processing, and speech-to-text conversion is stable and reliable. -- **1.2 Error Handling and Logging Improvements**: Enhance error handling to gracefully manage and log failures in audio recording or processing, ensuring the IDE remains stable. +- **1.2 Error Handling and Logging Improvements**: Enhance error handling to gracefully manage and log failures in audio recording or processing, ensuring the + IDE remains stable. - **1.3 Performance Optimization**: Optimize the performance of audio processing and speech-to-text conversion to minimize latency and resource consumption. - #### Phase 2: User Experience Enhancements -- **2.1 Configurable Settings**: Introduce settings allowing users to adjust audio sensitivity, specify preferred languages, and customize the speech-to-text engine. + +- **2.1 Configurable Settings**: Introduce settings allowing users to adjust audio sensitivity, specify preferred languages, and customize the speech-to-text + engine. - **2.2 Visual Feedback**: Implement visual indicators for recording status, audio levels, and processing activity to provide users with real-time feedback. - **2.3 Pause/Resume Capability**: Add functionality for users to pause and resume dictation, accommodating interruptions and breaks in speech. - #### Phase 3: Advanced Features -- **3.1 Command and Control**: Develop a set of voice commands that can control the IDE, such as opening files, navigating code, and executing builds. -- **3.2 Contextual Awareness**: Enhance the speech-to-text engine to understand and apply contextual clues from the surrounding code, improving accuracy for coding-specific terminology. -- **3.3 Multi-Language Support**: Expand speech-to-text capabilities to support multiple programming languages, adapting to syntax and common phrases used in different languages. +- **3.1 Command and Control**: Develop a set of voice commands that can control the IDE, such as opening files, navigating code, and executing builds. +- **3.2 Contextual Awareness**: Enhance the speech-to-text engine to understand and apply contextual clues from the surrounding code, improving accuracy for + coding-specific terminology. +- **3.3 Multi-Language Support**: Expand speech-to-text capabilities to support multiple programming languages, adapting to syntax and common phrases used in + different languages. #### Phase 4: Integration and Collaboration -- **4.1 Plugin Ecosystem**: Create an API that allows other plugins to extend and utilize the dictation capabilities, fostering a rich ecosystem of voice-enabled tools. -- **4.2 Collaboration Tools**: Integrate with collaboration tools to enable voice dictation in code reviews, pair programming sessions, and team meetings within the IDE. -- **4.3 Cloud-Based Processing Option**: Offer an option to use cloud-based speech-to-text services for improved accuracy and processing power, with considerations for privacy and security. +- **4.1 Plugin Ecosystem**: Create an API that allows other plugins to extend and utilize the dictation capabilities, fostering a rich ecosystem of + voice-enabled tools. +- **4.2 Collaboration Tools**: Integrate with collaboration tools to enable voice dictation in code reviews, pair programming sessions, and team meetings within + the IDE. +- **4.3 Cloud-Based Processing Option**: Offer an option to use cloud-based speech-to-text services for improved accuracy and processing power, with + considerations for privacy and security. #### Phase 5: Accessibility and Inclusivity -- **5.1 Accessibility Features**: Ensure the dictation feature is accessible, with support for users with disabilities, including visual impairments and motor difficulties. -- **5.2 Language and Dialect Inclusivity**: Expand language support to include a wide range of dialects and accents, ensuring inclusivity and usability for a global user base. -- **5.3 User Training and Documentation**: Provide comprehensive training materials and documentation to help users get the most out of the dictation features, including best practices for dictation in a coding environment. +- **5.1 Accessibility Features**: Ensure the dictation feature is accessible, with support for users with disabilities, including visual impairments and motor + difficulties. +- **5.2 Language and Dialect Inclusivity**: Expand language support to include a wide range of dialects and accents, ensuring inclusivity and usability for a + global user base. +- **5.3 User Training and Documentation**: Provide comprehensive training materials and documentation to help users get the most out of the dictation features, + including best practices for dictation in a coding environment. #### Phase 6: Continuous Improvement and Feedback + - **6.1 User Feedback Loop**: Establish a mechanism for collecting user feedback on dictation features, using insights to guide future development. - **6.2 Regular Updates**: Commit to regular updates, incorporating the latest advancements in speech-to-text technology and addressing emerging user needs. -- **6.3 Community Engagement**: Engage with the developer community to share tips, gather use cases, and promote innovative uses of dictation in software development. +- **6.3 Community Engagement**: Engage with the developer community to share tips, gather use cases, and promote innovative uses of dictation in software + development. -This roadmap outlines a comprehensive strategy for evolving the `VoiceToTextAction` class into a powerful tool that enhances productivity, fosters inclusivity, and revolutionizes the way developers interact with their IDE. +This roadmap outlines a comprehensive strategy for evolving the `VoiceToTextAction` class into a powerful tool that enhances productivity, fosters inclusivity, +and revolutionizes the way developers interact with their IDE. # kotlin\com\github\simiacryptus\aicoder\actions\generic\DiffChatAction.kt -Creating a feature development roadmap for the `DiffChatAction` class involves outlining the planned enhancements, improvements, and new capabilities that will be added over time. This roadmap will guide the development process, ensuring that the feature evolves to meet user needs and leverages new technologies effectively. Here's a proposed roadmap: - +Creating a feature development roadmap for the `DiffChatAction` class involves outlining the planned enhancements, improvements, and new capabilities that will +be added over time. This roadmap will guide the development process, ensuring that the feature evolves to meet user needs and leverages new technologies +effectively. Here's a proposed roadmap: #### Phase 1: Core Functionality Enhancement -- **Improved Diff Rendering**: Enhance the visual representation of diffs in the chat interface, making it easier for users to understand changes at a glance. -- **Selection Context Expansion**: Automatically include more context around selected text when initiating a diff chat, helping to provide clearer understanding for remote collaborators. -- **Performance Optimization**: Optimize the handling and processing of diffs, especially for large files or projects, to ensure smooth and responsive user experiences. +- **Improved Diff Rendering**: Enhance the visual representation of diffs in the chat interface, making it easier for users to understand changes at a glance. +- **Selection Context Expansion**: Automatically include more context around selected text when initiating a diff chat, helping to provide clearer understanding + for remote collaborators. +- **Performance Optimization**: Optimize the handling and processing of diffs, especially for large files or projects, to ensure smooth and responsive user + experiences. #### Phase 2: User Experience Improvements + - **Customizable UI**: Allow users to customize the appearance and layout of the diff chat interface, including themes and font sizes. - **Notification System**: Implement a notification system for users to receive updates about diff chats they are involved in or interested in. -- **Integration with Version Control Systems**: Enable direct integration with version control systems like Git, allowing users to initiate diff chats from within their VCS interface or apply diffs directly to their repositories. - +- **Integration with Version Control Systems**: Enable direct integration with version control systems like Git, allowing users to initiate diff chats from + within their VCS interface or apply diffs directly to their repositories. #### Phase 3: Collaboration and Accessibility Features -- **Real-Time Collaboration**: Introduce real-time editing and commenting within the diff chat, allowing multiple users to collaborate on a piece of code simultaneously. -- **Accessibility Enhancements**: Improve accessibility features, including keyboard navigation, screen reader support, and high-contrast themes, to ensure the tool is usable by developers with disabilities. -- **Language Support Expansion**: Expand support for additional programming languages and dialects, based on user feedback and emerging trends in software development. +- **Real-Time Collaboration**: Introduce real-time editing and commenting within the diff chat, allowing multiple users to collaborate on a piece of code + simultaneously. +- **Accessibility Enhancements**: Improve accessibility features, including keyboard navigation, screen reader support, and high-contrast themes, to ensure the + tool is usable by developers with disabilities. +- **Language Support Expansion**: Expand support for additional programming languages and dialects, based on user feedback and emerging trends in software + development. #### Phase 4: Advanced Functionalities -- **AI-Assisted Code Review**: Integrate AI-based tools to provide suggestions, identify potential issues, and offer improvements within the diff chat, helping to streamline the code review process. -- **Security and Compliance Tools**: Incorporate security scanning and compliance checking tools within the diff chat workflow, enabling teams to identify and address vulnerabilities early in the development process. -- **Analytics and Reporting**: Provide analytics and reporting features for teams to track changes, review patterns, and assess the impact of diffs over time, aiding in project management and planning. +- **AI-Assisted Code Review**: Integrate AI-based tools to provide suggestions, identify potential issues, and offer improvements within the diff chat, helping + to streamline the code review process. +- **Security and Compliance Tools**: Incorporate security scanning and compliance checking tools within the diff chat workflow, enabling teams to identify and + address vulnerabilities early in the development process. +- **Analytics and Reporting**: Provide analytics and reporting features for teams to track changes, review patterns, and assess the impact of diffs over time, + aiding in project management and planning. #### Phase 5: Ecosystem Integration -- **Plugin Ecosystem**: Develop a plugin ecosystem that allows third-party developers to extend and enhance the diff chat functionality, fostering innovation and customization. -- **Integration with Development Tools**: Enable seamless integration with popular development tools and IDEs, allowing developers to use diff chat within their existing workflows. -- **Community Features**: Introduce community features, such as public diff chat rooms, code snippets sharing, and expert assistance, to foster a community of practice around effective code collaboration. -This roadmap is designed to be iterative, with each phase building upon the previous ones. Feedback from users and developments in related technologies will inform adjustments and additions to the roadmap, ensuring that the `DiffChatAction` class remains a valuable tool for developers and teams. +- **Plugin Ecosystem**: Develop a plugin ecosystem that allows third-party developers to extend and enhance the diff chat functionality, fostering innovation + and customization. +- **Integration with Development Tools**: Enable seamless integration with popular development tools and IDEs, allowing developers to use diff chat within their + existing workflows. +- **Community Features**: Introduce community features, such as public diff chat rooms, code snippets sharing, and expert assistance, to foster a community of + practice around effective code collaboration. -# kotlin\com\github\simiacryptus\aicoder\actions\markdown\MarkdownListAction.kt +This roadmap is designed to be iterative, with each phase building upon the previous ones. Feedback from users and developments in related technologies will +inform adjustments and additions to the roadmap, ensuring that the `DiffChatAction` class remains a valuable tool for developers and teams. -The code provided outlines a Kotlin class `MarkdownListAction` that extends `BaseAction`. This class is designed to interact with Markdown files in an IntelliJ-based IDE, specifically to generate and insert a list of items into a Markdown document using a proxy service for item generation. The development roadmap for enhancing and expanding this feature could be structured as follows: +# kotlin\com\github\simiacryptus\aicoder\actions\markdown\MarkdownListAction.kt +The code provided outlines a Kotlin class `MarkdownListAction` that extends `BaseAction`. This class is designed to interact with Markdown files in an +IntelliJ-based IDE, specifically to generate and insert a list of items into a Markdown document using a proxy service for item generation. The development +roadmap for enhancing and expanding this feature could be structured as follows: #### Phase 1: Initial Setup and Refactoring + - **Review and Refactor Existing Code**: Ensure the current implementation follows best practices for readability, efficiency, and Kotlin coding standards. - **Improve Error Handling**: Implement more robust error handling around proxy interactions and document manipulations to gracefully handle failures. - #### Phase 2: Feature Enhancements + - **Custom Bullet Types**: Allow users to customize the bullet types used in the generated list (e.g., "-", "*", "+", numbered). - **Interactive Item Editing**: Implement a UI dialog that allows users to edit the generated list items before insertion. - **Support for Nested Lists**: Enhance the feature to recognize and generate nested lists based on the context or user input. - #### Phase 3: Integration and Usability Improvements -- **Contextual Activation**: Improve the logic for when the action is enabled, based on more nuanced analysis of the caret position and surrounding Markdown syntax. + +- **Contextual Activation**: Improve the logic for when the action is enabled, based on more nuanced analysis of the caret position and surrounding Markdown + syntax. - **Performance Optimization**: Optimize the interaction with the proxy and the manipulation of the document to improve the responsiveness of the action. - **User Preferences**: Allow users to set preferences for default bullet types, item generation models, and other settings through the IDE settings panel. - #### Phase 4: Advanced Features + - **Markdown Syntax Support**: Extend the feature to support additional Markdown syntax within list items, such as links, bold/italic text, and code snippets. - **AI-Powered Content Suggestions**: Leverage more advanced AI models to suggest content for the list items based on the context of the surrounding document. - **Collaborative List Generation**: Explore the possibility of collaborative list generation where multiple users can contribute to the list in real-time. - #### Phase 5: Testing and Documentation + - **Comprehensive Testing**: Develop a suite of unit and integration tests to cover various scenarios and ensure the reliability of the feature. - **Documentation and Tutorials**: Create detailed documentation and tutorials to help users understand how to use the new features effectively. - #### Phase 6: Release and Feedback Loop + - **Beta Release**: Release the new features in a beta version to gather user feedback. - **Feedback Incorporation**: Analyze user feedback to identify areas for improvement or additional features. - **Final Release**: Incorporate feedback and release the final version of the enhanced Markdown list action. - #### Phase 7: Future Directions + - **Extension to Other Formats**: Explore extending similar functionalities to other file formats supported by the IDE, such as reStructuredText or AsciiDoc. - **Integration with Other Tools**: Look into integrating this feature with other tools and platforms, such as content management systems or note-taking apps. -This roadmap provides a structured approach to developing the `MarkdownListAction` feature, focusing on enhancing functionality, usability, and integration, with an emphasis on user feedback and continuous improvement. +This roadmap provides a structured approach to developing the `MarkdownListAction` feature, focusing on enhancing functionality, usability, and integration, +with an emphasis on user feedback and continuous improvement. # kotlin\com\github\simiacryptus\aicoder\actions\generic\ReplaceWithSuggestionsAction.kt -Creating a feature development roadmap for the `ReplaceWithSuggestionsAction` class and its associated functionalities involves outlining the stages of development, from initial setup to advanced features and potential future enhancements. This roadmap will guide the development process, ensuring a structured approach to adding features and improving the `ReplaceWithSuggestionsAction` class. - +Creating a feature development roadmap for the `ReplaceWithSuggestionsAction` class and its associated functionalities involves outlining the stages of +development, from initial setup to advanced features and potential future enhancements. This roadmap will guide the development process, ensuring a structured +approach to adding features and improving the `ReplaceWithSuggestionsAction` class. #### Phase 1: Initial Setup and Core Functionality -- **Setup Project Environment**: Establish the project structure, including necessary dependencies such as Kotlin, IntelliJ Platform SDK, and any required libraries for API communication. -- **Implement Basic Selection Action**: Develop the base `SelectionAction` class to handle text selection within the IntelliJ editor. -- **Virtual API Interface**: Define the `VirtualAPI` interface to abstract the communication with the AI model, ensuring flexibility for future changes in the backend. +- **Setup Project Environment**: Establish the project structure, including necessary dependencies such as Kotlin, IntelliJ Platform SDK, and any required + libraries for API communication. +- **Implement Basic Selection Action**: Develop the base `SelectionAction` class to handle text selection within the IntelliJ editor. +- **Virtual API Interface**: Define the `VirtualAPI` interface to abstract the communication with the AI model, ensuring flexibility for future changes in the + backend. #### Phase 2: Integration with AI Services -- **ChatProxy Integration**: Integrate `ChatProxy` to communicate with AI services, using it to generate suggestions based on the selected text. -- **Implement Suggestion Retrieval**: Develop the logic to retrieve suggestions from the AI service, handling the communication and response parsing within the `processSelection` method. -- **UI for Suggestions**: Create a user interface component (e.g., a dialog with radio buttons) to display the AI-generated suggestions to the user, allowing them to select the most appropriate option. +- **ChatProxy Integration**: Integrate `ChatProxy` to communicate with AI services, using it to generate suggestions based on the selected text. +- **Implement Suggestion Retrieval**: Develop the logic to retrieve suggestions from the AI service, handling the communication and response parsing within the + `processSelection` method. +- **UI for Suggestions**: Create a user interface component (e.g., a dialog with radio buttons) to display the AI-generated suggestions to the user, allowing + them to select the most appropriate option. #### Phase 3: Usability Enhancements -- **Contextual Analysis**: Improve the suggestion mechanism by enhancing the contextual analysis before and after the selected text, ensuring more relevant suggestions are generated. -- **Configurable Settings**: Allow users to configure settings such as the AI model, temperature, and other parameters through the `AppSettingsState` class, providing flexibility and customization. -- **Performance Optimization**: Optimize the suggestion retrieval and processing to ensure a smooth and responsive user experience, even with large documents or complex selections. +- **Contextual Analysis**: Improve the suggestion mechanism by enhancing the contextual analysis before and after the selected text, ensuring more relevant + suggestions are generated. +- **Configurable Settings**: Allow users to configure settings such as the AI model, temperature, and other parameters through the `AppSettingsState` class, + providing flexibility and customization. +- **Performance Optimization**: Optimize the suggestion retrieval and processing to ensure a smooth and responsive user experience, even with large documents or + complex selections. #### Phase 4: Advanced Features -- **Multi-Language Support**: Extend the functionality to support multiple programming languages, adapting the context analysis and suggestion mechanisms accordingly. -- **Batch Processing**: Implement the ability to process multiple selections simultaneously, allowing users to apply suggestions to various parts of their code in one go. -- **Feedback Loop Integration**: Integrate a feedback mechanism where users can rate the suggestions, with this data being used to improve the AI model's accuracy over time. +- **Multi-Language Support**: Extend the functionality to support multiple programming languages, adapting the context analysis and suggestion mechanisms + accordingly. +- **Batch Processing**: Implement the ability to process multiple selections simultaneously, allowing users to apply suggestions to various parts of their code + in one go. +- **Feedback Loop Integration**: Integrate a feedback mechanism where users can rate the suggestions, with this data being used to improve the AI model's + accuracy over time. #### Phase 5: Future Enhancements -- **Plugin Ecosystem Integration**: Explore integration with other IntelliJ plugins to enhance functionality, such as using code formatting or linting tools in conjunction with the suggestions. -- **Machine Learning Model Training**: Investigate the possibility of training custom AI models based on user data and preferences, for more personalized and accurate suggestions. -- **Community Contribution**: Open the development for community contributions, allowing other developers to add new features, support more languages, or improve existing functionalities. -This roadmap provides a structured approach to developing the `ReplaceWithSuggestionsAction` class, from basic functionality to advanced features and potential future enhancements. Each phase builds upon the previous one, gradually increasing the complexity and capabilities of the class, with a focus on usability, performance, and extensibility. +- **Plugin Ecosystem Integration**: Explore integration with other IntelliJ plugins to enhance functionality, such as using code formatting or linting tools in + conjunction with the suggestions. +- **Machine Learning Model Training**: Investigate the possibility of training custom AI models based on user data and preferences, for more personalized and + accurate suggestions. +- **Community Contribution**: Open the development for community contributions, allowing other developers to add new features, support more languages, or + improve existing functionalities. -# kotlin\com\github\simiacryptus\aicoder\actions\SelectionAction.kt +This roadmap provides a structured approach to developing the `ReplaceWithSuggestionsAction` class, from basic functionality to advanced features and potential +future enhancements. Each phase builds upon the previous one, gradually increasing the complexity and capabilities of the class, with a focus on usability, +performance, and extensibility. -Creating a feature development roadmap for the `SelectionAction` class and its related components involves outlining a series of enhancements, optimizations, and new capabilities that can be added to enrich its functionality, improve its performance, and extend its applicability. Here's a proposed roadmap that spans short-term, mid-term, and long-term goals: +# kotlin\com\github\simiacryptus\aicoder\actions\SelectionAction.kt +Creating a feature development roadmap for the `SelectionAction` class and its related components involves outlining a series of enhancements, optimizations, +and new capabilities that can be added to enrich its functionality, improve its performance, and extend its applicability. Here's a proposed roadmap that spans +short-term, mid-term, and long-term goals: #### Short-Term Goals (1-3 Months) -1. **Refinement of Selection Mechanisms**: Improve the logic for determining the selection range, especially in edge cases where the current selection might not accurately represent the user's intent. -2. **Performance Optimization**: Profile the code to identify and optimize any performance bottlenecks, particularly in the `editorState` and `contextRanges` methods, which could be critical in large files. -3. **User Configuration Interface**: Develop a simple UI for configuring the behavior of `SelectionAction`, allowing users to set preferences for selection behavior, supported languages, and indentation styles. -4. **Documentation and Examples**: Create comprehensive documentation and usage examples for developers to understand how to extend and utilize the `SelectionAction` class effectively. +1. **Refinement of Selection Mechanisms**: Improve the logic for determining the selection range, especially in edge cases where the current selection might not + accurately represent the user's intent. +2. **Performance Optimization**: Profile the code to identify and optimize any performance bottlenecks, particularly in the `editorState` and `contextRanges` + methods, which could be critical in large files. +3. **User Configuration Interface**: Develop a simple UI for configuring the behavior of `SelectionAction`, allowing users to set preferences for selection + behavior, supported languages, and indentation styles. +4. **Documentation and Examples**: Create comprehensive documentation and usage examples for developers to understand how to extend and utilize the + `SelectionAction` class effectively. #### Mid-Term Goals (4-6 Months) -1. **Language Support Expansion**: Extend the `isLanguageSupported` method to include more programming languages, potentially leveraging community contributions to cover a broader spectrum. -2. **Context-Aware Selection Enhancement**: Enhance the context detection logic to make smarter decisions about the code selection based on the syntax and semantics of the target language. -3. **Integration with Version Control Systems**: Implement features that leverage version control system (VCS) data, such as highlighting changes within the selection or adjusting the selection based on recent edits. -4. **Testing Framework**: Develop a comprehensive testing framework to ensure the reliability of `SelectionAction` across different environments, languages, and editor states. +1. **Language Support Expansion**: Extend the `isLanguageSupported` method to include more programming languages, potentially leveraging community contributions + to cover a broader spectrum. +2. **Context-Aware Selection Enhancement**: Enhance the context detection logic to make smarter decisions about the code selection based on the syntax and + semantics of the target language. +3. **Integration with Version Control Systems**: Implement features that leverage version control system (VCS) data, such as highlighting changes within the + selection or adjusting the selection based on recent edits. +4. **Testing Framework**: Develop a comprehensive testing framework to ensure the reliability of `SelectionAction` across different environments, languages, and + editor states. #### Long-Term Goals (7-12 Months) -1. **Machine Learning-Based Selection**: Explore the use of machine learning models to predict and adjust code selections based on user behavior, codebase patterns, and context. -2. **Plugin Ecosystem**: Create an ecosystem around `SelectionAction` that allows developers to create and share plugins that add new features, support additional languages, or integrate with other tools. -3. **Collaborative Editing Features**: Implement features that support collaborative editing scenarios, such as shared selections, real-time editing suggestions, and conflict resolution tools. -4. **Cross-Platform Support**: Ensure that `SelectionAction` and its ecosystem are compatible with different IDEs and text editors, broadening its applicability and user base. +1. **Machine Learning-Based Selection**: Explore the use of machine learning models to predict and adjust code selections based on user behavior, codebase + patterns, and context. +2. **Plugin Ecosystem**: Create an ecosystem around `SelectionAction` that allows developers to create and share plugins that add new features, support + additional languages, or integrate with other tools. +3. **Collaborative Editing Features**: Implement features that support collaborative editing scenarios, such as shared selections, real-time editing + suggestions, and conflict resolution tools. +4. **Cross-Platform Support**: Ensure that `SelectionAction` and its ecosystem are compatible with different IDEs and text editors, broadening its applicability + and user base. #### Continuous Goals -- **User Feedback Loop**: Establish a continuous feedback loop with users to gather insights, feature requests, and bug reports, ensuring that development efforts align with user needs. -- **Code Quality and Maintenance**: Continuously refactor and improve the codebase to adhere to best practices, reduce technical debt, and ensure maintainability. -- **Community Engagement**: Foster a community around `SelectionAction` by encouraging contributions, providing support, and hosting events to discuss future directions. -This roadmap provides a structured approach to evolving the `SelectionAction` class and its ecosystem, ensuring it remains valuable, performant, and relevant to its users. +- **User Feedback Loop**: Establish a continuous feedback loop with users to gather insights, feature requests, and bug reports, ensuring that development + efforts align with user needs. +- **Code Quality and Maintenance**: Continuously refactor and improve the codebase to adhere to best practices, reduce technical debt, and ensure + maintainability. +- **Community Engagement**: Foster a community around `SelectionAction` by encouraging contributions, providing support, and hosting events to discuss future + directions. -# kotlin\com\github\simiacryptus\aicoder\actions\markdown\MarkdownImplementActionGroup.kt +This roadmap provides a structured approach to evolving the `SelectionAction` class and its ecosystem, ensuring it remains valuable, performant, and relevant to +its users. +# kotlin\com\github\simiacryptus\aicoder\actions\markdown\MarkdownImplementActionGroup.kt #### Feature Development Roadmap for Markdown Implement Action Group -The development roadmap for the Markdown Implement Action Group outlines the planned enhancements, new features, and improvements. This roadmap is designed to provide clarity on the direction of the project and to set expectations for stakeholders and contributors. The timeline and features are subject to change based on feedback, resource availability, and emerging priorities. - +The development roadmap for the Markdown Implement Action Group outlines the planned enhancements, new features, and improvements. This roadmap is designed to +provide clarity on the direction of the project and to set expectations for stakeholders and contributors. The timeline and features are subject to change based +on feedback, resource availability, and emerging priorities. ##### Phase 1: Foundation and Initial Release + - **Q2 2023** - - **Feature Completion**: Finalize the initial set of supported languages for markdown code blocks. Ensure the core functionality, including language detection and code block implementation, is robust and tested. - - **Documentation**: Complete documentation for the current codebase, ensuring that each class, method, and significant logic block is well-documented for future contributors and maintainers. + - **Feature Completion**: Finalize the initial set of supported languages for markdown code blocks. Ensure the core functionality, including language + detection and code block implementation, is robust and tested. + - **Documentation**: Complete documentation for the current codebase, ensuring that each class, method, and significant logic block is well-documented for + future contributors and maintainers. - **Initial Release**: Release the first version of the Markdown Implement Action Group, making it available for use within the specified IDE environment. - ##### Phase 2: Expansion and Integration + - **Q3 2023** - - **Language Support Expansion**: Based on user feedback and usage patterns, expand the list of supported languages for markdown code blocks. Prioritize languages that are in high demand among the user base. - - **Integration with Other Tools**: Explore and implement integrations with other tools and plugins within the IDE ecosystem to enhance the utility and accessibility of the Markdown Implement Action Group. + - **Language Support Expansion**: Based on user feedback and usage patterns, expand the list of supported languages for markdown code blocks. Prioritize + languages that are in high demand among the user base. + - **Integration with Other Tools**: Explore and implement integrations with other tools and plugins within the IDE ecosystem to enhance the utility and + accessibility of the Markdown Implement Action Group. - **Performance Optimization**: Analyze performance metrics and optimize the code to reduce latency, especially for large files or complex code blocks. - ##### Phase 3: Advanced Features and Customization -- **Q4 2023** - - **Custom Code Templates**: Introduce the ability for users to define custom code templates for different languages, allowing for more personalized and context-aware code block generation. - - **Advanced Language Detection**: Enhance the language detection algorithm to more accurately infer the programming language from the context or content of the selection. - - **User Preferences and Settings**: Implement a settings panel that allows users to customize various aspects of the Markdown Implement Action Group, including default languages, code formatting preferences, and integration options. +- **Q4 2023** + - **Custom Code Templates**: Introduce the ability for users to define custom code templates for different languages, allowing for more personalized and + context-aware code block generation. + - **Advanced Language Detection**: Enhance the language detection algorithm to more accurately infer the programming language from the context or content of + the selection. + - **User Preferences and Settings**: Implement a settings panel that allows users to customize various aspects of the Markdown Implement Action Group, + including default languages, code formatting preferences, and integration options. ##### Phase 4: Community and Ecosystem -- **Q1 2024** - - **Community Contributions**: Open the project to community contributions, including language support, bug fixes, and feature enhancements. Establish guidelines and processes for contributing. - - **Plugin Ecosystem**: Foster the development of an ecosystem around the Markdown Implement Action Group, encouraging the creation of plugins or extensions that add new features or integrate with other services. - - **Feedback Loop**: Implement a structured feedback loop with users to gather insights, feature requests, and bug reports. Use this feedback to inform the development roadmap and prioritize new features. +- **Q1 2024** + - **Community Contributions**: Open the project to community contributions, including language support, bug fixes, and feature enhancements. Establish + guidelines and processes for contributing. + - **Plugin Ecosystem**: Foster the development of an ecosystem around the Markdown Implement Action Group, encouraging the creation of plugins or extensions + that add new features or integrate with other services. + - **Feedback Loop**: Implement a structured feedback loop with users to gather insights, feature requests, and bug reports. Use this feedback to inform the + development roadmap and prioritize new features. ##### Phase 5: Sustainability and Growth + - **Q2 2024 and Beyond** - - **Sustainability Practices**: Implement practices to ensure the long-term sustainability of the project, including automated testing, continuous integration, and documentation updates. - - **Growth Strategy**: Develop and execute a strategy to grow the user base, including marketing efforts, community engagement, and partnerships with educational institutions or coding bootcamps. - - **Continuous Improvement**: Commit to ongoing improvement of the Markdown Implement Action Group, regularly releasing updates that enhance functionality, usability, and performance based on user feedback and technological advancements. + - **Sustainability Practices**: Implement practices to ensure the long-term sustainability of the project, including automated testing, continuous + integration, and documentation updates. + - **Growth Strategy**: Develop and execute a strategy to grow the user base, including marketing efforts, community engagement, and partnerships with + educational institutions or coding bootcamps. + - **Continuous Improvement**: Commit to ongoing improvement of the Markdown Implement Action Group, regularly releasing updates that enhance functionality, + usability, and performance based on user feedback and technological advancements. -This roadmap is a living document and will be updated periodically to reflect progress, changes in priorities, and new opportunities. Feedback from users, contributors, and stakeholders is highly valued and will play a crucial role in shaping the future direction of the Markdown Implement Action Group. +This roadmap is a living document and will be updated periodically to reflect progress, changes in priorities, and new opportunities. Feedback from users, +contributors, and stakeholders is highly valued and will play a crucial role in shaping the future direction of the Markdown Implement Action Group. # kotlin\com\github\simiacryptus\aicoder\ApplicationEvents.kt -Creating a feature development roadmap for the `ApplicationEvents` class within the `com.github.simiacryptus.aicoder` package involves outlining the future enhancements, improvements, and additions planned for this component. The roadmap will be structured into short-term, mid-term, and long-term goals, considering the current functionalities such as application activation handling, initialization of services like `OutputInterceptor`, `ClientManager`, and various `ApplicationServices`. - +Creating a feature development roadmap for the `ApplicationEvents` class within the `com.simiacryptus.aicoder` package involves outlining the future +enhancements, improvements, and additions planned for this component. The roadmap will be structured into short-term, mid-term, and long-term goals, considering +the current functionalities such as application activation handling, initialization of services like `OutputInterceptor`, `ClientManager`, and various +`ApplicationServices`. #### Short-Term Goals (0-3 Months) -1. **Refinement of Context Class Loader Handling**: Improve the handling of the thread's context class loader during application activation to ensure compatibility with a wider range of IDE versions and reduce potential for class loading issues. +1. **Refinement of Context Class Loader Handling**: Improve the handling of the thread's context class loader during application activation to ensure + compatibility with a wider range of IDE versions and reduce potential for class loading issues. -2. **Enhanced Error Handling and Logging**: Implement more robust error handling and logging mechanisms within the `init` method and other parts of the class to aid in troubleshooting and improve the stability of the plugin. +2. **Enhanced Error Handling and Logging**: Implement more robust error handling and logging mechanisms within the `init` method and other parts of the class to + aid in troubleshooting and improve the stability of the plugin. 3. **Performance Optimization**: Analyze and optimize the performance of the initialization process to reduce the impact on IDE startup time. -4. **User Documentation**: Develop comprehensive user documentation and in-line code comments to improve understandability and ease of use for developers integrating or contributing to the plugin. - +4. **User Documentation**: Develop comprehensive user documentation and in-line code comments to improve understandability and ease of use for developers + integrating or contributing to the plugin. #### Mid-Term Goals (4-8 Months) -1. **Dynamic Plugin Configuration**: Introduce a configuration interface within the IDE settings to allow users to customize the behavior of the `ApplicationEvents` class and its associated services without needing to modify the code. +1. **Dynamic Plugin Configuration**: Introduce a configuration interface within the IDE settings to allow users to customize the behavior of the + `ApplicationEvents` class and its associated services without needing to modify the code. -2. **Service Extension Points**: Develop extension points for `ApplicationServices` to allow third-party developers to extend or replace the default implementations of services like `ClientManager`, `UsageManager`, etc. +2. **Service Extension Points**: Develop extension points for `ApplicationServices` to allow third-party developers to extend or replace the default + implementations of services like `ClientManager`, `UsageManager`, etc. -3. **Security Enhancements**: Implement additional security measures for authentication and authorization processes, including support for OAuth and other secure authentication methods. - -4. **Integration Testing**: Establish a comprehensive suite of integration tests to ensure that changes to the `ApplicationEvents` class and related services do not negatively impact functionality or performance. +3. **Security Enhancements**: Implement additional security measures for authentication and authorization processes, including support for OAuth and other + secure authentication methods. +4. **Integration Testing**: Establish a comprehensive suite of integration tests to ensure that changes to the `ApplicationEvents` class and related services do + not negatively impact functionality or performance. #### Long-Term Goals (9-12 Months and Beyond) -1. **AI-Assisted Coding Features**: Leverage the `IdeaOpenAIClient` to introduce new AI-assisted coding features, such as code suggestions, bug detection, and automated refactoring suggestions. +1. **AI-Assisted Coding Features**: Leverage the `IdeaOpenAIClient` to introduce new AI-assisted coding features, such as code suggestions, bug detection, and + automated refactoring suggestions. -2. **Cloud Storage Support**: Extend the `StorageInterface` to support cloud storage options, enabling users to synchronize their usage data and settings across multiple devices. +2. **Cloud Storage Support**: Extend the `StorageInterface` to support cloud storage options, enabling users to synchronize their usage data and settings across + multiple devices. -3. **Plugin Ecosystem Development**: Foster a community of developers around the plugin by providing clear contribution guidelines, a plugin development SDK, and hosting community-driven plugin extensions. +3. **Plugin Ecosystem Development**: Foster a community of developers around the plugin by providing clear contribution guidelines, a plugin development SDK, + and hosting community-driven plugin extensions. -4. **Cross-Platform Compatibility**: Ensure full compatibility of the plugin with all major IDEs supported by the IntelliJ platform, including WebStorm, PyCharm, and others. +4. **Cross-Platform Compatibility**: Ensure full compatibility of the plugin with all major IDEs supported by the IntelliJ platform, including WebStorm, + PyCharm, and others. -By following this roadmap, the development team can systematically enhance the `ApplicationEvents` class and its associated functionalities, ensuring that the plugin remains a valuable and cutting-edge tool for developers working within the IntelliJ platform ecosystem. +By following this roadmap, the development team can systematically enhance the `ApplicationEvents` class and its associated functionalities, ensuring that the +plugin remains a valuable and cutting-edge tool for developers working within the IntelliJ platform ecosystem. # kotlin\com\github\simiacryptus\aicoder\config\ActionSettingsRegistry.kt -The code provided is part of a larger project aimed at enhancing the functionality of an IDE (Integrated Development Environment) by allowing dynamic actions based on user configurations and scripts. The roadmap for further development of this feature can be divided into several key milestones to ensure a structured and efficient approach. Here's a proposed feature development roadmap: - +The code provided is part of a larger project aimed at enhancing the functionality of an IDE (Integrated Development Environment) by allowing dynamic actions +based on user configurations and scripts. The roadmap for further development of this feature can be divided into several key milestones to ensure a structured +and efficient approach. Here's a proposed feature development roadmap: #### Phase 1: Foundation and Stability -- **Refactor and Clean Up**: Begin by refactoring the existing codebase for clarity, maintainability, and efficiency. This includes optimizing data structures, improving error handling, and ensuring consistent coding standards. -- **Enhanced Error Reporting**: Improve error reporting mechanisms to provide users with clear, actionable feedback when dynamic actions fail to load or execute. -- **Unit Testing**: Develop a comprehensive suite of unit tests to cover the core functionalities, ensuring that future changes do not break existing features. +- **Refactor and Clean Up**: Begin by refactoring the existing codebase for clarity, maintainability, and efficiency. This includes optimizing data structures, + improving error handling, and ensuring consistent coding standards. +- **Enhanced Error Reporting**: Improve error reporting mechanisms to provide users with clear, actionable feedback when dynamic actions fail to load or + execute. +- **Unit Testing**: Develop a comprehensive suite of unit tests to cover the core functionalities, ensuring that future changes do not break existing features. #### Phase 2: User Experience and Usability -- **UI Improvements**: Enhance the user interface for configuring actions, making it more intuitive and user-friendly. This could involve better categorization of actions, search functionality, and a preview feature for action outcomes. -- **Documentation and Examples**: Create detailed documentation and provide examples for users to understand how to create and configure their actions effectively. -- **Feedback Mechanism**: Implement a feedback mechanism within the IDE plugin to allow users to report issues or suggest improvements directly from the plugin. +- **UI Improvements**: Enhance the user interface for configuring actions, making it more intuitive and user-friendly. This could involve better categorization + of actions, search functionality, and a preview feature for action outcomes. +- **Documentation and Examples**: Create detailed documentation and provide examples for users to understand how to create and configure their actions + effectively. +- **Feedback Mechanism**: Implement a feedback mechanism within the IDE plugin to allow users to report issues or suggest improvements directly from the plugin. #### Phase 3: Advanced Features and Integration -- **Language Support Expansion**: Extend support for scripting dynamic actions to other programming languages beyond Kotlin, such as Python or JavaScript, to cater to a broader user base. -- **Version Control Integration**: Integrate with version control systems (e.g., Git) to manage action scripts and configurations, enabling versioning, sharing, and collaboration among team members. -- **Performance Optimization**: Optimize the performance of dynamic action loading and execution, ensuring minimal impact on the IDE's responsiveness and startup time. +- **Language Support Expansion**: Extend support for scripting dynamic actions to other programming languages beyond Kotlin, such as Python or JavaScript, to + cater to a broader user base. +- **Version Control Integration**: Integrate with version control systems (e.g., Git) to manage action scripts and configurations, enabling versioning, sharing, + and collaboration among team members. +- **Performance Optimization**: Optimize the performance of dynamic action loading and execution, ensuring minimal impact on the IDE's responsiveness and + startup time. #### Phase 4: Community and Ecosystem -- **Plugin Marketplace**: Develop a marketplace or repository where users can share and discover custom actions created by others, fostering a community around the plugin. -- **Extensibility API**: Provide an API that allows other developers to extend or build upon the dynamic actions feature, encouraging innovation and the development of new functionalities. -- **Analytics and Telemetry**: Implement optional analytics to gather insights on how the feature is being used, which can inform future development priorities and improvements. +- **Plugin Marketplace**: Develop a marketplace or repository where users can share and discover custom actions created by others, fostering a community around + the plugin. +- **Extensibility API**: Provide an API that allows other developers to extend or build upon the dynamic actions feature, encouraging innovation and the + development of new functionalities. +- **Analytics and Telemetry**: Implement optional analytics to gather insights on how the feature is being used, which can inform future development priorities + and improvements. #### Phase 5: Long-term Support and Evolution + - **Regular Updates**: Commit to regular updates of the plugin, including bug fixes, performance improvements, and compatibility with new versions of the IDE. -- **User Surveys and Research**: Conduct periodic surveys and user research to understand changing needs and usage patterns, guiding the future direction of the feature. -- **Open Source Community Engagement**: If applicable, engage with the open-source community for collaborative development, code reviews, and feature suggestions, leveraging the collective expertise to enhance the feature. +- **User Surveys and Research**: Conduct periodic surveys and user research to understand changing needs and usage patterns, guiding the future direction of the + feature. +- **Open Source Community Engagement**: If applicable, engage with the open-source community for collaborative development, code reviews, and feature + suggestions, leveraging the collective expertise to enhance the feature. -This roadmap provides a structured approach to developing the dynamic actions feature, focusing on foundational improvements, user experience, advanced functionalities, community building, and long-term evolution. +This roadmap provides a structured approach to developing the dynamic actions feature, focusing on foundational improvements, user experience, advanced +functionalities, community building, and long-term evolution. # kotlin\com\github\simiacryptus\aicoder\config\AppSettingsComponent.kt -Creating a feature development roadmap for the `AppSettingsComponent` class involves outlining the future enhancements, improvements, and additions planned for this component. This roadmap will guide the development process, ensuring that the component evolves to meet user needs and integrates seamlessly with the broader application ecosystem. Here's a proposed roadmap: - +Creating a feature development roadmap for the `AppSettingsComponent` class involves outlining the future enhancements, improvements, and additions planned for +this component. This roadmap will guide the development process, ensuring that the component evolves to meet user needs and integrates seamlessly with the +broader application ecosystem. Here's a proposed roadmap: #### Phase 1: Usability Enhancements -- **UI Improvements**: Refine the user interface for better usability and accessibility. This includes enhancing the layout, adding tooltips for each setting to explain its purpose, and improving the overall aesthetic appeal. -- **Validation and Feedback**: Implement input validation for fields like "Listening Port" to ensure users enter valid data. Provide immediate feedback on errors or successful changes to help users correct mistakes and understand the impact of their configurations. +- **UI Improvements**: Refine the user interface for better usability and accessibility. This includes enhancing the layout, adding tooltips for each setting to + explain its purpose, and improving the overall aesthetic appeal. +- **Validation and Feedback**: Implement input validation for fields like "Listening Port" to ensure users enter valid data. Provide immediate feedback on + errors or successful changes to help users correct mistakes and understand the impact of their configurations. #### Phase 2: Feature Expansion -- **Advanced Logging Options**: Expand the logging capabilities to include filtering by log level, tagging, and searching within the API log. This will help users more effectively debug and understand the behavior of their applications. -- **Custom Model Support**: Allow users to add custom models to the "Model" ComboBox, enabling integration with models outside the predefined set. This could include support for specifying model URLs or uploading model files directly. -- **Security Enhancements**: Introduce more robust security features for sensitive information, such as encrypting the API Key field and providing secure storage options. +- **Advanced Logging Options**: Expand the logging capabilities to include filtering by log level, tagging, and searching within the API log. This will help + users more effectively debug and understand the behavior of their applications. +- **Custom Model Support**: Allow users to add custom models to the "Model" ComboBox, enabling integration with models outside the predefined set. This could + include support for specifying model URLs or uploading model files directly. +- **Security Enhancements**: Introduce more robust security features for sensitive information, such as encrypting the API Key field and providing secure + storage options. #### Phase 3: Integration and Automation -- **Project-Specific Settings**: Enable project-specific configurations, allowing different settings for each project within the IDE. This would involve integrating more deeply with the project management features of the IDE. -- **Automated Actions**: Develop a system for triggering actions based on specific events or conditions within the IDE or the application. For example, automatically clearing the API log when it reaches a certain size or after a specified duration. -- **API Extensions**: Provide an API for other plugins to interact with `AppSettingsComponent`, enabling them to read settings, subscribe to changes, or even modify configurations programmatically. +- **Project-Specific Settings**: Enable project-specific configurations, allowing different settings for each project within the IDE. This would involve + integrating more deeply with the project management features of the IDE. +- **Automated Actions**: Develop a system for triggering actions based on specific events or conditions within the IDE or the application. For example, + automatically clearing the API log when it reaches a certain size or after a specified duration. +- **API Extensions**: Provide an API for other plugins to interact with `AppSettingsComponent`, enabling them to read settings, subscribe to changes, or even + modify configurations programmatically. #### Phase 4: Performance and Scalability -- **Optimization**: Analyze and optimize the performance of the settings component, ensuring that it operates efficiently even with extensive configurations or in large projects. -- **Scalability Enhancements**: Ensure that the component scales seamlessly with the growth of the application and the IDE, maintaining performance and usability. +- **Optimization**: Analyze and optimize the performance of the settings component, ensuring that it operates efficiently even with extensive configurations or + in large projects. +- **Scalability Enhancements**: Ensure that the component scales seamlessly with the growth of the application and the IDE, maintaining performance and + usability. #### Phase 5: Community and Feedback -- **User Feedback Loop**: Implement mechanisms for collecting user feedback directly through the component interface, such as feature requests, bug reports, and usability suggestions. -- **Community Contributions**: Open up parts of the component for community contributions, including localization, custom models, and UI themes. This could involve setting up a repository and guidelines for contributions. +- **User Feedback Loop**: Implement mechanisms for collecting user feedback directly through the component interface, such as feature requests, bug reports, and + usability suggestions. +- **Community Contributions**: Open up parts of the component for community contributions, including localization, custom models, and UI themes. This could + involve setting up a repository and guidelines for contributions. #### Phase 6: Future-Proofing -- **Adaptation to IDE Updates**: Regularly update the component to adapt to new versions of the IDE, ensuring compatibility and taking advantage of new APIs and features. -- **Emerging Technologies**: Keep an eye on emerging technologies and trends in AI and development tools to incorporate innovative features that could enhance the component. -This roadmap is a living document and should be revisited and revised based on user feedback, technological advancements, and the evolving needs of the development community. +- **Adaptation to IDE Updates**: Regularly update the component to adapt to new versions of the IDE, ensuring compatibility and taking advantage of new APIs and + features. +- **Emerging Technologies**: Keep an eye on emerging technologies and trends in AI and development tools to incorporate innovative features that could enhance + the component. -# kotlin\com\github\simiacryptus\aicoder\config\ActionTable.kt +This roadmap is a living document and should be revisited and revised based on user feedback, technological advancements, and the evolving needs of the +development community. -The `ActionTable` class is a sophisticated component designed for managing action settings within an application, particularly useful in environments like IntelliJ IDEA plugins. This class allows users to enable/disable actions, edit their display text, and manage their identifiers through a user-friendly graphical interface. Below is a proposed feature development roadmap to enhance its functionality, usability, and integration capabilities. +# kotlin\com\github\simiacryptus\aicoder\config\ActionTable.kt +The `ActionTable` class is a sophisticated component designed for managing action settings within an application, particularly useful in environments like +IntelliJ IDEA plugins. This class allows users to enable/disable actions, edit their display text, and manage their identifiers through a user-friendly +graphical interface. Below is a proposed feature development roadmap to enhance its functionality, usability, and integration capabilities. #### Phase 1: Core Functionality Enhancements -- **Undo/Redo Support**: Implement undo/redo functionality for all table operations, including add, remove, and edit actions. This will improve user experience by allowing them to revert their changes easily. -- **Batch Operations**: Enable users to select multiple rows for batch operations like enabling/disabling and removing actions. This will enhance usability for managing a large number of actions. -- **Search and Filter**: Introduce a search bar to filter actions by their display text or ID, helping users quickly find specific actions. +- **Undo/Redo Support**: Implement undo/redo functionality for all table operations, including add, remove, and edit actions. This will improve user experience + by allowing them to revert their changes easily. +- **Batch Operations**: Enable users to select multiple rows for batch operations like enabling/disabling and removing actions. This will enhance usability for + managing a large number of actions. +- **Search and Filter**: Introduce a search bar to filter actions by their display text or ID, helping users quickly find specific actions. #### Phase 2: Usability Improvements -- **Column Resizing and Sorting**: Allow users to resize columns and sort the table by clicking on column headers. Sorting by "Enabled" status, "Display Text", or "ID" will make it easier for users to organize and find actions. -- **Persistence of User Preferences**: Save and restore user preferences such as column widths, sorting order, and last selected action. This personalization will enhance the user experience. -- **Improved Validation and Feedback**: Implement more robust validation for the inputs (e.g., checking for duplicate IDs) and provide immediate, clear feedback on errors or successful operations. +- **Column Resizing and Sorting**: Allow users to resize columns and sort the table by clicking on column headers. Sorting by "Enabled" status, "Display Text", + or "ID" will make it easier for users to organize and find actions. +- **Persistence of User Preferences**: Save and restore user preferences such as column widths, sorting order, and last selected action. This personalization + will enhance the user experience. +- **Improved Validation and Feedback**: Implement more robust validation for the inputs (e.g., checking for duplicate IDs) and provide immediate, clear feedback + on errors or successful operations. #### Phase 3: Advanced Features -- **Custom Action Parameters**: Support defining and editing custom parameters for actions. This could involve a more complex dialog for editing actions, where users can specify additional metadata or configuration options. -- **Integration with Version Control Systems**: Offer integration with version control systems to track changes to action configurations. This feature would be particularly useful for teams working on shared projects, enabling them to see who made changes and revert them if necessary. -- **Export/Import Configuration**: Allow users to export and import action settings. This feature will enable easy sharing of configurations between different instances of the application or among team members. +- **Custom Action Parameters**: Support defining and editing custom parameters for actions. This could involve a more complex dialog for editing actions, where + users can specify additional metadata or configuration options. +- **Integration with Version Control Systems**: Offer integration with version control systems to track changes to action configurations. This feature would be + particularly useful for teams working on shared projects, enabling them to see who made changes and revert them if necessary. +- **Export/Import Configuration**: Allow users to export and import action settings. This feature will enable easy sharing of configurations between different + instances of the application or among team members. #### Phase 4: Performance and Scalability -- **Lazy Loading for Large Datasets**: Implement lazy loading and virtual scrolling for handling a large number of actions without performance degradation. This will ensure the UI remains responsive even with thousands of actions. -- **Concurrency Handling**: Ensure that the UI can handle concurrent modifications safely, especially important in a collaborative environment where multiple users might be editing the action settings simultaneously. +- **Lazy Loading for Large Datasets**: Implement lazy loading and virtual scrolling for handling a large number of actions without performance degradation. This + will ensure the UI remains responsive even with thousands of actions. +- **Concurrency Handling**: Ensure that the UI can handle concurrent modifications safely, especially important in a collaborative environment where multiple + users might be editing the action settings simultaneously. #### Phase 5: Extensibility -- **Plugin Architecture for Custom Actions**: Develop a plugin architecture that allows third-party developers to create and distribute custom actions. This will open up possibilities for extending the application's functionality. -- **API for Programmatic Access**: Expose an API for programmatically accessing and modifying action settings. This would be useful for automation scripts and integrating with other tools or systems. +- **Plugin Architecture for Custom Actions**: Develop a plugin architecture that allows third-party developers to create and distribute custom actions. This + will open up possibilities for extending the application's functionality. +- **API for Programmatic Access**: Expose an API for programmatically accessing and modifying action settings. This would be useful for automation scripts and + integrating with other tools or systems. #### Phase 6: Documentation and Tutorials + - **Comprehensive Documentation**: Provide detailed documentation covering all features, including examples and best practices for managing action settings. - **Video Tutorials**: Create video tutorials demonstrating common workflows and advanced features to help users get the most out of the application. -This roadmap aims to evolve the `ActionTable` class into a more powerful and user-friendly tool, catering to a wide range of use cases and enhancing the overall user experience. +This roadmap aims to evolve the `ActionTable` class into a more powerful and user-friendly tool, catering to a wide range of use cases and enhancing the overall +user experience. # kotlin\com\github\simiacryptus\aicoder\config\AppSettingsConfigurable.kt -Developing a feature for a software project involves planning and executing various tasks. Below is a feature development roadmap for enhancing the `AppSettingsConfigurable` class, which is part of a larger project aimed at managing application settings through a user interface. This roadmap outlines the steps needed to introduce new features, improve existing functionalities, and ensure the robustness and usability of the feature. - +Developing a feature for a software project involves planning and executing various tasks. Below is a feature development roadmap for enhancing the +`AppSettingsConfigurable` class, which is part of a larger project aimed at managing application settings through a user interface. This roadmap outlines the +steps needed to introduce new features, improve existing functionalities, and ensure the robustness and usability of the feature. #### Phase 1: Requirements Gathering and Analysis + - **Identify Stakeholder Needs:** Engage with users, developers, and other stakeholders to gather requirements for new settings or improvements. - **Analyze Current Implementation:** Review the existing `AppSettingsConfigurable` class to understand its capabilities and limitations. - **Define Feature Scope:** Clearly outline what new settings or improvements will be developed. - #### Phase 2: Design + - **UI/UX Design:** Design the user interface changes or enhancements for the new settings, ensuring a user-friendly experience. - **Architecture Design:** Plan how the new features will integrate with the existing `AppSettingsConfigurable` class and the overall application architecture. - **Security and Privacy Considerations:** Ensure that the new features adhere to security best practices and respect user privacy. - #### Phase 3: Development + - **Setup Development Environment:** Prepare the necessary development tools and frameworks. -- **Implement New Features:** Develop the new settings or improvements as per the design documents. This includes updating methods like `read()` and `write()` to handle the new settings. +- **Implement New Features:** Develop the new settings or improvements as per the design documents. This includes updating methods like `read()` and `write()` + to handle the new settings. - **Refactor and Optimize:** Refactor any existing code for better maintainability and performance. - #### Phase 4: Testing + - **Unit Testing:** Write unit tests for new methods and logic to ensure they work as expected. - **Integration Testing:** Test the integration of the new features with the existing application to identify any issues. - **User Acceptance Testing (UAT):** Allow a select group of users to test the new features and provide feedback. - #### Phase 5: Documentation + - **Code Documentation:** Update code comments and documentation to reflect the new features and any significant changes. - **User Documentation:** Create or update user manuals, help documents, or online help sections to guide users on the new features. - #### Phase 6: Deployment + - **Prepare Release:** Package the new version of the application, including the updated `AppSettingsConfigurable` class. - **Deploy to Production:** Release the new version to users, following the project's deployment strategies. - **Monitor and Support:** Monitor the application for any issues and provide support to users as needed. - #### Phase 7: Feedback and Iteration + - **Gather Feedback:** Collect feedback from users on the new features. - **Analyze Feedback:** Identify any areas for improvement or additional features based on user feedback. - **Plan Next Iteration:** Based on feedback, plan the next set of features or improvements to be developed. -This roadmap provides a structured approach to developing new features for the `AppSettingsConfigurable` class, ensuring that the development process is efficient, the new features meet user needs, and the application remains robust and user-friendly. +This roadmap provides a structured approach to developing new features for the `AppSettingsConfigurable` class, ensuring that the development process is +efficient, the new features meet user needs, and the application remains robust and user-friendly. # kotlin\com\github\simiacryptus\aicoder\config\SimpleEnvelope.kt -Creating a feature development roadmap for the `SimpleEnvelope` class within the `com.github.simiacryptus.aicoder.config` package involves outlining a series of enhancements and new functionalities that can be added to make the class more robust, versatile, and useful in various applications. Here's a proposed roadmap: - +Creating a feature development roadmap for the `SimpleEnvelope` class within the `com.simiacryptus.aicoder.config` package involves outlining a series of +enhancements and new functionalities that can be added to make the class more robust, versatile, and useful in various applications. Here's a proposed roadmap: #### Phase 1: Basic Enhancements -- **Immutable Value Support**: Introduce a way to make `SimpleEnvelope` immutable after its creation. This could involve adding a boolean flag that, once the value is set, prevents further modifications. -- **Validation**: Implement value validation upon setting it. This could involve a simple non-null check or more complex validations based on predefined criteria (e.g., string length, pattern matching). +- **Immutable Value Support**: Introduce a way to make `SimpleEnvelope` immutable after its creation. This could involve adding a boolean flag that, once the + value is set, prevents further modifications. +- **Validation**: Implement value validation upon setting it. This could involve a simple non-null check or more complex validations based on predefined + criteria (e.g., string length, pattern matching). #### Phase 2: Functional Extensions -- **Serialization Support**: Add support for serializing and deserializing `SimpleEnvelope` instances to and from JSON/XML. This would make it easier to use `SimpleEnvelope` in web services or applications that rely on these data formats. -- **Event Listeners**: Implement a mechanism to attach event listeners that get notified when the value changes. This would be useful in scenarios where actions need to be triggered by changes to the `SimpleEnvelope`'s value. +- **Serialization Support**: Add support for serializing and deserializing `SimpleEnvelope` instances to and from JSON/XML. This would make it easier to use + `SimpleEnvelope` in web services or applications that rely on these data formats. +- **Event Listeners**: Implement a mechanism to attach event listeners that get notified when the value changes. This would be useful in scenarios where actions + need to be triggered by changes to the `SimpleEnvelope`'s value. #### Phase 3: Integration and Compatibility -- **Framework Compatibility**: Ensure compatibility with popular frameworks such as Spring or Jakarta EE. This could involve creating custom annotations or integrators that make it easier to use `SimpleEnvelope` as a configuration or request body object. -- **Type Adapters**: Develop adapters or converters that allow `SimpleEnvelope` to seamlessly work with different types of contained values, beyond just strings. This could include support for numbers, dates, or even complex objects. +- **Framework Compatibility**: Ensure compatibility with popular frameworks such as Spring or Jakarta EE. This could involve creating custom annotations or + integrators that make it easier to use `SimpleEnvelope` as a configuration or request body object. +- **Type Adapters**: Develop adapters or converters that allow `SimpleEnvelope` to seamlessly work with different types of contained values, beyond just + strings. This could include support for numbers, dates, or even complex objects. #### Phase 4: Security and Performance Enhancements -- **Encryption Support**: Add optional support for encrypting and decrypting the value stored in `SimpleEnvelope`. This would be particularly useful for sensitive information that needs to be protected. -- **Performance Optimization**: Profile the class and identify any performance bottlenecks. Implement optimizations such as lazy initialization or caching strategies to improve the performance, especially in high-load scenarios. +- **Encryption Support**: Add optional support for encrypting and decrypting the value stored in `SimpleEnvelope`. This would be particularly useful for + sensitive information that needs to be protected. +- **Performance Optimization**: Profile the class and identify any performance bottlenecks. Implement optimizations such as lazy initialization or caching + strategies to improve the performance, especially in high-load scenarios. #### Phase 5: Community and Documentation -- **Comprehensive Documentation**: Develop detailed documentation covering all features of `SimpleEnvelope`, including code examples, use cases, and integration guides. -- **Community Feedback**: Open a channel for users to provide feedback, report bugs, or suggest features. This could involve setting up a GitHub repository, forum, or social media group dedicated to `SimpleEnvelope`. +- **Comprehensive Documentation**: Develop detailed documentation covering all features of `SimpleEnvelope`, including code examples, use cases, and integration + guides. +- **Community Feedback**: Open a channel for users to provide feedback, report bugs, or suggest features. This could involve setting up a GitHub repository, + forum, or social media group dedicated to `SimpleEnvelope`. #### Phase 6: Advanced Features -- **Generic Type Support**: Refactor `SimpleEnvelope` to support generic types, allowing it to hold any type of value, not just strings. This would significantly increase its versatility. + +- **Generic Type Support**: Refactor `SimpleEnvelope` to support generic types, allowing it to hold any type of value, not just strings. This would + significantly increase its versatility. - **Distributed Support**: Add features that enable `SimpleEnvelope` to be used in distributed systems, such as versioning or conflict resolution mechanisms. -This roadmap provides a structured approach to developing the `SimpleEnvelope` class, starting with basic enhancements and gradually introducing more complex features. Each phase builds upon the previous ones, ensuring a steady progression towards making `SimpleEnvelope` a powerful and flexible tool for developers. +This roadmap provides a structured approach to developing the `SimpleEnvelope` class, starting with basic enhancements and gradually introducing more complex +features. Each phase builds upon the previous ones, ensuring a steady progression towards making `SimpleEnvelope` a powerful and flexible tool for developers. # kotlin\com\github\simiacryptus\aicoder\config\AppSettingsState.kt -Creating a feature development roadmap for the `AppSettingsState` class within the context of an IntelliJ SDK plugin involves planning out enhancements, new functionalities, and improvements over time. This roadmap will outline potential directions for the development of the plugin, focusing on enhancing user experience, expanding capabilities, and maintaining compatibility and performance. The roadmap is divided into short-term, mid-term, and long-term goals. - +Creating a feature development roadmap for the `AppSettingsState` class within the context of an IntelliJ SDK plugin involves planning out enhancements, new +functionalities, and improvements over time. This roadmap will outline potential directions for the development of the plugin, focusing on enhancing user +experience, expanding capabilities, and maintaining compatibility and performance. The roadmap is divided into short-term, mid-term, and long-term goals. #### Short-Term Goals (0-3 Months) 1. **Improve Configuration UI:** - - Develop a more intuitive and user-friendly settings interface that allows users to easily configure the plugin settings such as `temperature`, `modelName`, `listeningPort`, etc. - - Implement validation checks for user inputs to prevent configuration errors. + +- Develop a more intuitive and user-friendly settings interface that allows users to easily configure the plugin settings such as `temperature`, `modelName`, + `listeningPort`, etc. +- Implement validation checks for user inputs to prevent configuration errors. 2. **Enhance Recent Commands Feature:** - - Improve the UI for accessing and managing recent commands, making it easier for users to reuse previous inputs. - - Add the ability to categorize and search through the recent commands for better organization. + +- Improve the UI for accessing and managing recent commands, making it easier for users to reuse previous inputs. +- Add the ability to categorize and search through the recent commands for better organization. 3. **API Key Security:** - - Implement a more secure way to store and handle the `apiKey` to enhance security and protect user data. + +- Implement a more secure way to store and handle the `apiKey` to enhance security and protect user data. 4. **Localization and Internationalization:** - - Begin the process of localizing the plugin UI and messages to support multiple languages, starting with major languages such as Spanish, Chinese, and German. +- Begin the process of localizing the plugin UI and messages to support multiple languages, starting with major languages such as Spanish, Chinese, and + German. #### Mid-Term Goals (4-8 Months) 1. **Expand Model Support:** - - Integrate additional OpenAI models into the plugin, providing users with a wider range of AI capabilities. - - Allow users to customize and extend the model configurations for advanced use cases. + +- Integrate additional OpenAI models into the plugin, providing users with a wider range of AI capabilities. +- Allow users to customize and extend the model configurations for advanced use cases. 2. **Performance Optimization:** - - Optimize the plugin's performance, especially in terms of API call efficiency and response handling, to ensure a smooth user experience even under heavy load. + +- Optimize the plugin's performance, especially in terms of API call efficiency and response handling, to ensure a smooth user experience even under heavy + load. 3. **Advanced Error Handling:** - - Develop a comprehensive error handling and reporting system that provides users with clear, actionable feedback on issues such as API failures, network problems, or configuration errors. + +- Develop a comprehensive error handling and reporting system that provides users with clear, actionable feedback on issues such as API failures, network + problems, or configuration errors. 4. **Plugin Analytics:** - - Introduce optional, privacy-respecting analytics to gather insights on how the plugin is used, which features are most popular, and what areas need improvement. +- Introduce optional, privacy-respecting analytics to gather insights on how the plugin is used, which features are most popular, and what areas need + improvement. #### Long-Term Goals (9-12 Months) 1. **Collaborative Features:** - - Explore the possibility of adding collaborative features that allow teams to share configurations, models, and commands within the plugin environment. + +- Explore the possibility of adding collaborative features that allow teams to share configurations, models, and commands within the plugin environment. 2. **Extend IDE Integration:** - - Broaden the plugin's integration with other aspects of the IntelliJ platform, such as offering AI-assisted coding suggestions, code analysis, and more interactive development tools. + +- Broaden the plugin's integration with other aspects of the IntelliJ platform, such as offering AI-assisted coding suggestions, code analysis, and more + interactive development tools. 3. **Custom AI Model Training:** - - Investigate the feasibility of allowing users to train custom models directly from the plugin, leveraging OpenAI's APIs for personalized AI functionalities. + +- Investigate the feasibility of allowing users to train custom models directly from the plugin, leveraging OpenAI's APIs for personalized AI functionalities. 4. **Community and Ecosystem:** - - Foster a community around the plugin by setting up forums, contributing guides, and encouraging third-party extensions or integrations. + +- Foster a community around the plugin by setting up forums, contributing guides, and encouraging third-party extensions or integrations. 5. **Sustainability and Open Source:** - - Consider open-sourcing parts of the plugin to encourage community contributions, improve transparency, and ensure the long-term sustainability of the project. -This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. Regular reviews and updates to the roadmap will ensure that the development efforts remain aligned with user needs and industry trends. +- Consider open-sourcing parts of the plugin to encourage community contributions, improve transparency, and ensure the long-term sustainability of the + project. -# kotlin\com\github\simiacryptus\aicoder\config\Name.kt +This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. Regular reviews and updates to the roadmap will +ensure that the development efforts remain aligned with user needs and industry trends. -Creating a feature development roadmap for the `Name` annotation within the `com.github.simiacryptus.aicoder.config` package involves outlining a series of planned enhancements and functionalities that will be added over time. This roadmap will guide the development process, ensuring that the annotation becomes more versatile and useful in various coding scenarios. Here's a proposed roadmap: +# kotlin\com\github\simiacryptus\aicoder\config\Name.kt +Creating a feature development roadmap for the `Name` annotation within the `com.simiacryptus.aicoder.config` package involves outlining a series of planned +enhancements and functionalities that will be added over time. This roadmap will guide the development process, ensuring that the annotation becomes more +versatile and useful in various coding scenarios. Here's a proposed roadmap: #### Phase 1: Initial Release -- **Current State**: The `Name` annotation is designed to be used at runtime (`AnnotationRetention.RUNTIME`) and takes a single `String` value as its parameter. This initial setup allows developers to annotate elements with a custom name. +- **Current State**: The `Name` annotation is designed to be used at runtime (`AnnotationRetention.RUNTIME`) and takes a single `String` value as its parameter. + This initial setup allows developers to annotate elements with a custom name. #### Phase 2: Documentation and Examples + - **Objective**: Provide comprehensive documentation and examples on how to use the `Name` annotation effectively. - **Actions**: - Create detailed documentation explaining the purpose of the `Name` annotation and its application. - Publish examples demonstrating how to annotate classes, methods, and fields with `Name` and how to retrieve these annotations at runtime. - #### Phase 3: Enhanced Usability + - **Objective**: Improve the usability of the `Name` annotation by introducing additional parameters and features. - **Actions**: - Add optional parameters to the annotation for additional metadata, such as `description` or `category`. - Implement default values for the new parameters, ensuring backward compatibility. - #### Phase 4: Integration with Other Tools + - **Objective**: Ensure the `Name` annotation can be easily integrated with documentation generators, IDEs, and other development tools. - **Actions**: - - Develop plugins or extensions for popular IDEs (e.g., IntelliJ IDEA, Eclipse) that recognize the `Name` annotation and provide enhanced editing features, such as auto-completion and tooltips. + - Develop plugins or extensions for popular IDEs (e.g., IntelliJ IDEA, Eclipse) that recognize the `Name` annotation and provide enhanced editing features, + such as auto-completion and tooltips. - Work with authors of documentation generation tools to support the `Name` annotation, allowing it to influence generated docs directly. - #### Phase 5: Advanced Features + - **Objective**: Add advanced features to the `Name` annotation to support complex development scenarios. - **Actions**: - Introduce the ability to group annotations and apply them conditionally based on the development environment or build configuration. - Explore the possibility of adding support for annotation inheritance, where a class or method inherits the `Name` annotation from its parent or interface. - #### Phase 6: Community Feedback and Iteration + - **Objective**: Gather feedback from the developer community and iterate on the `Name` annotation features. - **Actions**: - Set up a feedback mechanism, such as a GitHub repository or forum, where developers can suggest improvements or report issues. - Regularly review feedback and prioritize the implementation of requested features and bug fixes. - #### Phase 7: Finalization and Stability + - **Objective**: Ensure the `Name` annotation is stable, well-documented, and widely adopted. - **Actions**: - Conduct thorough testing, including unit tests and integration tests, to ensure reliability. @@ -1670,450 +2085,584 @@ This roadmap is a living document and may evolve based on technological advancem # kotlin\com\github\simiacryptus\aicoder\config\MRUItems.kt -Creating a feature development roadmap for the `MRUItems` class involves planning the addition of new features, improvements, and optimizations to enhance its functionality, performance, and usability. Below is a proposed roadmap that outlines potential milestones and features to be developed: - +Creating a feature development roadmap for the `MRUItems` class involves planning the addition of new features, improvements, and optimizations to enhance its +functionality, performance, and usability. Below is a proposed roadmap that outlines potential milestones and features to be developed: #### Phase 1: Core Functionality Enhancement -- **Refinement of History Management**: Improve the efficiency of adding, removing, and managing items in both `mostUsedHistory` and `mostRecentHistory`. This could involve optimizing data structures or algorithms used for managing history. -- **Dynamic History Limit Configuration**: Allow users to dynamically adjust the `historyLimit` at runtime, providing flexibility in how much history is retained. +- **Refinement of History Management**: Improve the efficiency of adding, removing, and managing items in both `mostUsedHistory` and `mostRecentHistory`. This + could involve optimizing data structures or algorithms used for managing history. +- **Dynamic History Limit Configuration**: Allow users to dynamically adjust the `historyLimit` at runtime, providing flexibility in how much history is + retained. #### Phase 2: Feature Expansion -- **History Persistence**: Implement functionality to save and load history from a persistent storage (e.g., file system, database), enabling history to be retained across application restarts. -- **History Item Metadata**: Extend history items to include metadata such as timestamps, frequency of use, and custom tags. This would allow for more sophisticated history management and querying capabilities. +- **History Persistence**: Implement functionality to save and load history from a persistent storage (e.g., file system, database), enabling history to be + retained across application restarts. +- **History Item Metadata**: Extend history items to include metadata such as timestamps, frequency of use, and custom tags. This would allow for more + sophisticated history management and querying capabilities. #### Phase 3: Usability and Accessibility Improvements -- **API Documentation and Examples**: Create comprehensive documentation and examples demonstrating how to use the `MRUItems` class and its features effectively. -- **Configuration via External Files**: Allow configuration settings, such as `historyLimit`, to be specified in external configuration files, making it easier to adjust settings without modifying code. +- **API Documentation and Examples**: Create comprehensive documentation and examples demonstrating how to use the `MRUItems` class and its features + effectively. +- **Configuration via External Files**: Allow configuration settings, such as `historyLimit`, to be specified in external configuration files, making it easier + to adjust settings without modifying code. #### Phase 4: Performance Optimization and Scalability -- **Performance Benchmarking**: Conduct benchmark tests to identify performance bottlenecks and areas for optimization. -- **Scalability Enhancements**: Implement improvements to ensure the `MRUItems` class can efficiently handle large volumes of history items without significant degradation in performance. +- **Performance Benchmarking**: Conduct benchmark tests to identify performance bottlenecks and areas for optimization. +- **Scalability Enhancements**: Implement improvements to ensure the `MRUItems` class can efficiently handle large volumes of history items without significant + degradation in performance. #### Phase 5: Advanced Features and Integrations -- **Integration with Other Systems**: Develop integrations that allow `MRUItems` to interact with other systems or applications, such as IDEs or command-line tools, to automatically track and manage history in different contexts. -- **Predictive Suggestions Based on History**: Implement machine learning algorithms to analyze history and provide predictive suggestions for the most relevant items based on usage patterns. +- **Integration with Other Systems**: Develop integrations that allow `MRUItems` to interact with other systems or applications, such as IDEs or command-line + tools, to automatically track and manage history in different contexts. +- **Predictive Suggestions Based on History**: Implement machine learning algorithms to analyze history and provide predictive suggestions for the most relevant + items based on usage patterns. #### Phase 6: Security and Privacy Enhancements -- **Data Encryption for History Storage**: Implement encryption for history items stored persistently, ensuring that sensitive information is protected. -- **Privacy Controls**: Provide users with controls to manage the privacy of their history, including options to exclude specific items from being tracked or to clear history. +- **Data Encryption for History Storage**: Implement encryption for history items stored persistently, ensuring that sensitive information is protected. +- **Privacy Controls**: Provide users with controls to manage the privacy of their history, including options to exclude specific items from being tracked or to + clear history. #### Phase 7: Community Feedback and Continuous Improvement + - **User Feedback Loop**: Establish mechanisms for collecting user feedback on the `MRUItems` class and its features, such as surveys or issue trackers. -- **Continuous Feature Updates**: Based on user feedback and emerging use cases, continuously evaluate and implement new features and improvements to address the evolving needs of users. +- **Continuous Feature Updates**: Based on user feedback and emerging use cases, continuously evaluate and implement new features and improvements to address + the evolving needs of users. -This roadmap is intended to guide the development of the `MRUItems` class over time, ensuring that it remains useful, efficient, and adaptable to the needs of its users. +This roadmap is intended to guide the development of the `MRUItems` class over time, ensuring that it remains useful, efficient, and adaptable to the needs of +its users. # kotlin\com\github\simiacryptus\aicoder\config\StaticAppSettingsConfigurable.kt -Creating a feature development roadmap for the `StaticAppSettingsConfigurable` class and its associated functionalities involves outlining the future enhancements, bug fixes, and new features that could be implemented to improve the user experience and functionality of the application settings configuration within a plugin environment. Below is a proposed roadmap categorized into short-term, mid-term, and long-term goals. - +Creating a feature development roadmap for the `StaticAppSettingsConfigurable` class and its associated functionalities involves outlining the future +enhancements, bug fixes, and new features that could be implemented to improve the user experience and functionality of the application settings configuration +within a plugin environment. Below is a proposed roadmap categorized into short-term, mid-term, and long-term goals. #### Short-term Goals (1-3 months) -1. **UI Improvements**: Enhance the user interface for better usability and accessibility. This includes refining the layout, improving the responsiveness of the UI components, and adding tooltips for better clarity on what each setting does. -2. **Validation and Error Handling**: Implement input validation for all settings fields to ensure that the user inputs are within acceptable ranges or formats. Improve error handling to provide more informative feedback to users. -3. **Performance Optimization**: Analyze and optimize the performance of the settings apply process, ensuring that changes are applied efficiently without significant delays. +1. **UI Improvements**: Enhance the user interface for better usability and accessibility. This includes refining the layout, improving the responsiveness of + the UI components, and adding tooltips for better clarity on what each setting does. +2. **Validation and Error Handling**: Implement input validation for all settings fields to ensure that the user inputs are within acceptable ranges or formats. + Improve error handling to provide more informative feedback to users. +3. **Performance Optimization**: Analyze and optimize the performance of the settings apply process, ensuring that changes are applied efficiently without + significant delays. #### Mid-term Goals (4-6 months) + 1. **Feature Enhancements**: - - **Token Counter**: Reintroduce the token counter feature with improvements, such as real-time updates and better integration with the rest of the settings. - - **API Log Management**: Enhance the API log management capabilities, allowing users to easily view, search, and filter log entries from within the plugin. + +- **Token Counter**: Reintroduce the token counter feature with improvements, such as real-time updates and better integration with the rest of the settings. +- **API Log Management**: Enhance the API log management capabilities, allowing users to easily view, search, and filter log entries from within the plugin. + 2. **Security Enhancements**: Implement security measures for sensitive information, such as encrypting the API key stored in the settings. 3. **Customization Options**: Provide more customization options for users, allowing them to tailor the plugin's behavior and appearance to their preferences. - #### Long-term Goals (7-12 months) -1. **Extensibility**: Develop an API or plugin architecture that allows third-party developers to extend or add new features to the settings configurable, fostering a community-driven approach to feature development. -2. **Internationalization and Localization**: Prepare the plugin for a global audience by implementing internationalization and localization support, allowing users to use the plugin in their preferred language. -3. **Advanced Developer Tools**: Introduce advanced developer tools and settings, such as custom API request builders, performance profiling tools, and more detailed control over the plugin's internal workings. -4. **Integration with Other Services**: Explore and implement integrations with other services and APIs, enhancing the plugin's functionality and making it a more versatile tool for developers. +1. **Extensibility**: Develop an API or plugin architecture that allows third-party developers to extend or add new features to the settings configurable, + fostering a community-driven approach to feature development. +2. **Internationalization and Localization**: Prepare the plugin for a global audience by implementing internationalization and localization support, allowing + users to use the plugin in their preferred language. +3. **Advanced Developer Tools**: Introduce advanced developer tools and settings, such as custom API request builders, performance profiling tools, and more + detailed control over the plugin's internal workings. +4. **Integration with Other Services**: Explore and implement integrations with other services and APIs, enhancing the plugin's functionality and making it a + more versatile tool for developers. #### Continuous Goals -- **User Feedback Loop**: Establish a continuous feedback loop with users to gather insights, feature requests, and bug reports. This feedback will be crucial in prioritizing the development roadmap and ensuring the plugin meets the users' needs. -- **Documentation and Tutorials**: Continuously update the documentation and create tutorials to help users understand how to use the new features and get the most out of the plugin. -- **Testing and Quality Assurance**: Implement a robust testing framework to ensure new features and changes do not introduce regressions or negatively impact the user experience. -This roadmap is subject to change based on user feedback, technological advancements, and the evolving needs of the plugin's user base. Regularly reviewing and adjusting the roadmap will be key to the successful development and enhancement of the `StaticAppSettingsConfigurable` class and its functionalities. +- **User Feedback Loop**: Establish a continuous feedback loop with users to gather insights, feature requests, and bug reports. This feedback will be crucial + in prioritizing the development roadmap and ensuring the plugin meets the users' needs. +- **Documentation and Tutorials**: Continuously update the documentation and create tutorials to help users understand how to use the new features and get the + most out of the plugin. +- **Testing and Quality Assurance**: Implement a robust testing framework to ensure new features and changes do not introduce regressions or negatively impact + the user experience. -# kotlin\com\github\simiacryptus\aicoder\ui\EditorMenu.kt +This roadmap is subject to change based on user feedback, technological advancements, and the evolving needs of the plugin's user base. Regularly reviewing and +adjusting the roadmap will be key to the successful development and enhancement of the `StaticAppSettingsConfigurable` class and its functionalities. -Creating a feature development roadmap for the `EditorMenu` class within the context of an IntelliJ plugin involves outlining the planned enhancements, improvements, and new functionalities that will be added over time. This roadmap will guide the development process, ensuring that the plugin remains useful, user-friendly, and aligned with the needs of its users. Below is a proposed roadmap, divided into short-term, mid-term, and long-term goals. +# kotlin\com\github\simiacryptus\aicoder\ui\EditorMenu.kt +Creating a feature development roadmap for the `EditorMenu` class within the context of an IntelliJ plugin involves outlining the planned enhancements, +improvements, and new functionalities that will be added over time. This roadmap will guide the development process, ensuring that the plugin remains useful, +user-friendly, and aligned with the needs of its users. Below is a proposed roadmap, divided into short-term, mid-term, and long-term goals. #### Short-Term Goals (1-3 Months) -- **Enhance Menu Customization**: Improve the `EditorMenu` class to allow users to more easily customize the actions available in the editor's context menu. This could involve creating a GUI within the plugin settings where users can add, remove, or reorder actions. -- **Performance Optimization**: Analyze and optimize the performance of the `EditorMenu` class, ensuring that the dynamic loading of actions does not negatively impact the editor's responsiveness. -- **Context-Sensitive Actions**: Develop a system within `EditorMenu` to show or hide actions based on the context of the editor (e.g., the type of file being edited or the cursor's position within the file). +- **Enhance Menu Customization**: Improve the `EditorMenu` class to allow users to more easily customize the actions available in the editor's context menu. + This could involve creating a GUI within the plugin settings where users can add, remove, or reorder actions. +- **Performance Optimization**: Analyze and optimize the performance of the `EditorMenu` class, ensuring that the dynamic loading of actions does not negatively + impact the editor's responsiveness. +- **Context-Sensitive Actions**: Develop a system within `EditorMenu` to show or hide actions based on the context of the editor (e.g., the type of file being + edited or the cursor's position within the file). #### Mid-Term Goals (4-6 Months) -- **Integration with External Tools**: Extend the `EditorMenu` to allow integration with external tools and services, enabling actions that can, for example, format code using an external formatter, check code quality, or even run custom scripts. -- **User-Defined Macros**: Implement a feature that lets users create their own macros or scripts that can be executed from the `EditorMenu`. This would allow for highly customized workflows tailored to individual needs. -- **Localization and Internationalization**: Begin the process of localizing the plugin, making the `EditorMenu` and its actions accessible in multiple languages. This will help in expanding the user base to non-English speaking users. +- **Integration with External Tools**: Extend the `EditorMenu` to allow integration with external tools and services, enabling actions that can, for example, + format code using an external formatter, check code quality, or even run custom scripts. +- **User-Defined Macros**: Implement a feature that lets users create their own macros or scripts that can be executed from the `EditorMenu`. This would allow + for highly customized workflows tailored to individual needs. +- **Localization and Internationalization**: Begin the process of localizing the plugin, making the `EditorMenu` and its actions accessible in multiple + languages. This will help in expanding the user base to non-English speaking users. #### Long-Term Goals (7-12 Months) -- **AI-Assisted Code Generation**: Integrate AI-based code suggestions and generation into the `EditorMenu`, allowing users to generate code snippets or complete functions based on brief descriptions or comments. -- **Collaborative Editing Features**: Explore the possibility of adding collaborative editing features to the `EditorMenu`, enabling multiple users to work on the same file simultaneously with a real-time update and conflict resolution system. -- **Comprehensive User Feedback System**: Implement a comprehensive feedback system that allows users to report bugs, request features, and suggest improvements directly through the plugin. Use this feedback to continuously improve the `EditorMenu` and other aspects of the plugin. +- **AI-Assisted Code Generation**: Integrate AI-based code suggestions and generation into the `EditorMenu`, allowing users to generate code snippets or + complete functions based on brief descriptions or comments. +- **Collaborative Editing Features**: Explore the possibility of adding collaborative editing features to the `EditorMenu`, enabling multiple users to work on + the same file simultaneously with a real-time update and conflict resolution system. +- **Comprehensive User Feedback System**: Implement a comprehensive feedback system that allows users to report bugs, request features, and suggest improvements + directly through the plugin. Use this feedback to continuously improve the `EditorMenu` and other aspects of the plugin. #### Continuous Improvement -- **Regular Updates and Maintenance**: Ensure that the plugin is regularly updated to remain compatible with the latest versions of IntelliJ and to address any security vulnerabilities or bugs that are discovered. -- **User Engagement and Community Building**: Engage with the plugin's user community through forums, social media, and other channels to gather insights, foster a sense of community, and encourage contributions from users. -This roadmap is a living document and should be revisited and revised regularly based on user feedback, technological advancements, and the changing needs of the developer community. +- **Regular Updates and Maintenance**: Ensure that the plugin is regularly updated to remain compatible with the latest versions of IntelliJ and to address any + security vulnerabilities or bugs that are discovered. +- **User Engagement and Community Building**: Engage with the plugin's user community through forums, social media, and other channels to gather insights, + foster a sense of community, and encourage contributions from users. -# kotlin\com\github\simiacryptus\aicoder\ui\ModelSelectionWidgetFactory.kt +This roadmap is a living document and should be revisited and revised regularly based on user feedback, technological advancements, and the changing needs of +the developer community. -Developing a feature, especially for a software application, involves a series of steps from conceptualization to deployment. Below is a structured roadmap for the development of a feature, using the `ModelSelectionWidgetFactory` and its components as a reference example. This roadmap can be adapted to fit the development process of various features in different projects. +# kotlin\com\github\simiacryptus\aicoder\ui\ModelSelectionWidgetFactory.kt +Developing a feature, especially for a software application, involves a series of steps from conceptualization to deployment. Below is a structured roadmap for +the development of a feature, using the `ModelSelectionWidgetFactory` and its components as a reference example. This roadmap can be adapted to fit the +development process of various features in different projects. #### 1. Conceptualization and Planning -- **Idea Generation:** Identify the need for a new feature. For the `ModelSelectionWidgetFactory`, the need was to allow users to select a model directly from the status bar. + +- **Idea Generation:** Identify the need for a new feature. For the `ModelSelectionWidgetFactory`, the need was to allow users to select a model directly from + the status bar. - **Feasibility Study:** Assess the technical feasibility and the potential impact on the user experience. - **Requirements Gathering:** Define what the feature will do, its inputs, outputs, and how it will interact with other parts of the system. - **Design Mockups:** Create UI/UX designs if the feature has a user interface component. - #### 2. Technical Design + - **Architecture Design:** Outline the technical architecture, including how the feature will be integrated into the existing system. - **Data Flow Diagrams:** Detail how data will flow through the feature, identifying any external dependencies. - **Component Design:** Break down the feature into smaller components, like the `ModelSelectionWidget` and its interaction with `AppSettingsState`. - #### 3. Development + - **Setup Development Environment:** Ensure all necessary tools and dependencies are in place. -- **Coding:** Start coding the feature, adhering to coding standards and best practices. For instance, implementing the `ModelSelectionWidget` class and its methods. +- **Coding:** Start coding the feature, adhering to coding standards and best practices. For instance, implementing the `ModelSelectionWidget` class and its + methods. - **Code Reviews:** Conduct regular code reviews to maintain code quality and catch issues early. - #### 4. Testing + - **Unit Testing:** Write and run unit tests for individual components to ensure they work as expected in isolation. - **Integration Testing:** Test the feature in conjunction with other parts of the system to ensure it integrates smoothly. - **User Acceptance Testing (UAT):** Have end-users test the feature to ensure it meets their needs and expectations. - #### 5. Documentation + - **Code Documentation:** Document the code and its components for future reference and maintenance. - **User Documentation:** Create user manuals or help documents explaining how to use the feature. - #### 6. Deployment + - **Deployment Planning:** Plan the deployment, including timing and any necessary downtime. - **Release:** Deploy the feature to the production environment. - **Monitoring:** Monitor the feature for any issues post-release. - #### 7. Maintenance and Iteration + - **Feedback Collection:** Collect user feedback on the feature. - **Performance Monitoring:** Monitor the feature's performance and any impact on the overall system. - **Iterative Improvement:** Based on feedback and performance data, make necessary adjustments and improvements to the feature. - #### 8. Retirement + - **Deprecation Plan:** If the feature becomes obsolete, plan its deprecation and communicate this to users. - **Data Migration:** If necessary, migrate data to a new system or feature. - **Removal:** Remove the feature from the product in a way that minimizes disruption to users. -This roadmap provides a comprehensive guide for developing a feature from idea to retirement, ensuring a structured approach to development, deployment, and maintenance. +This roadmap provides a comprehensive guide for developing a feature from idea to retirement, ensuring a structured approach to development, deployment, and +maintenance. # kotlin\com\github\simiacryptus\aicoder\config\UIAdapter.kt -The `UIAdapter` class serves as a foundational component for managing user interface (UI) settings in an IntelliJ plugin, specifically designed for the AICoder project. This class abstracts the common functionalities needed for creating, displaying, and managing UI components and their associated settings. To further enhance and expand its capabilities, a feature development roadmap is proposed below. This roadmap outlines a series of planned enhancements and new features aimed at improving usability, performance, and extensibility. - +The `UIAdapter` class serves as a foundational component for managing user interface (UI) settings in an IntelliJ plugin, specifically designed for the AICoder +project. This class abstracts the common functionalities needed for creating, displaying, and managing UI components and their associated settings. To further +enhance and expand its capabilities, a feature development roadmap is proposed below. This roadmap outlines a series of planned enhancements and new features +aimed at improving usability, performance, and extensibility. #### Phase 1: Usability Improvements -1. **Dynamic UI Updates**: Implement functionality to allow dynamic updates to the UI based on changes in settings without requiring a restart or manual refresh. -2. **Validation Framework**: Develop a validation framework that can be used to validate user inputs in real-time, providing immediate feedback to users. -3. **Enhanced Error Handling**: Improve error handling mechanisms to provide more informative and user-friendly error messages, especially for common mistakes or misconfigurations. +1. **Dynamic UI Updates**: Implement functionality to allow dynamic updates to the UI based on changes in settings without requiring a restart or manual + refresh. +2. **Validation Framework**: Develop a validation framework that can be used to validate user inputs in real-time, providing immediate feedback to users. +3. **Enhanced Error Handling**: Improve error handling mechanisms to provide more informative and user-friendly error messages, especially for common mistakes + or misconfigurations. #### Phase 2: Performance Optimization -1. **Lazy Loading**: Optimize the UI initialization process by implementing lazy loading techniques, ensuring that UI components are only created and loaded when needed. -2. **Memory Management**: Introduce more robust memory management practices, including the disposal of unused components and resources, to prevent memory leaks and improve overall performance. -3. **Concurrency Management**: Enhance concurrency management to ensure that UI updates and settings modifications are handled efficiently, especially in multi-threaded environments. +1. **Lazy Loading**: Optimize the UI initialization process by implementing lazy loading techniques, ensuring that UI components are only created and loaded + when needed. +2. **Memory Management**: Introduce more robust memory management practices, including the disposal of unused components and resources, to prevent memory leaks + and improve overall performance. +3. **Concurrency Management**: Enhance concurrency management to ensure that UI updates and settings modifications are handled efficiently, especially in + multi-threaded environments. #### Phase 3: Extensibility and Customization -1. **Plugin Extension Points**: Create extension points that allow other developers to extend or customize the UI and settings management functionalities, fostering a more flexible and extensible plugin ecosystem. -2. **Theme Support**: Implement support for customizable UI themes, enabling users to personalize the appearance of the settings UI according to their preferences. -3. **Internationalization (i18n)**: Add internationalization support to make the UI and messages easily translatable, catering to a global user base. +1. **Plugin Extension Points**: Create extension points that allow other developers to extend or customize the UI and settings management functionalities, + fostering a more flexible and extensible plugin ecosystem. +2. **Theme Support**: Implement support for customizable UI themes, enabling users to personalize the appearance of the settings UI according to their + preferences. +3. **Internationalization (i18n)**: Add internationalization support to make the UI and messages easily translatable, catering to a global user base. #### Phase 4: Advanced Features + 1. **Settings Profiles**: Introduce the concept of settings profiles, allowing users to save, switch between, and manage multiple configurations easily. 2. **Cloud Synchronization**: Develop a cloud synchronization feature that enables users to sync their settings across multiple installations or devices. -3. **Analytics and Feedback**: Incorporate analytics and feedback mechanisms to gather user insights and preferences, guiding future development priorities and improvements. - +3. **Analytics and Feedback**: Incorporate analytics and feedback mechanisms to gather user insights and preferences, guiding future development priorities and + improvements. #### Phase 5: Documentation and Community Engagement -1. **Comprehensive Documentation**: Create detailed documentation covering all aspects of the UIAdapter class and its usage, including examples, best practices, and troubleshooting tips. -2. **Community Forum**: Establish a community forum or platform for users and developers to share tips, ask questions, and collaborate on custom extensions or themes. -3. **Contribution Guidelines**: Publish clear contribution guidelines to encourage and facilitate contributions from the developer community, including bug fixes, feature enhancements, and new plugins. -This roadmap is designed to be iterative, with each phase building upon the successes and lessons learned from the previous ones. Feedback from users and contributors will be invaluable in prioritizing and refining these features as development progresses. +1. **Comprehensive Documentation**: Create detailed documentation covering all aspects of the UIAdapter class and its usage, including examples, best practices, + and troubleshooting tips. +2. **Community Forum**: Establish a community forum or platform for users and developers to share tips, ask questions, and collaborate on custom extensions or + themes. +3. **Contribution Guidelines**: Publish clear contribution guidelines to encourage and facilitate contributions from the developer community, including bug + fixes, feature enhancements, and new plugins. -# kotlin\com\github\simiacryptus\aicoder\config\UsageTable.kt +This roadmap is designed to be iterative, with each phase building upon the successes and lessons learned from the previous ones. Feedback from users and +contributors will be invaluable in prioritizing and refining these features as development progresses. -Creating a feature development roadmap for the `UsageTable` class involves planning out enhancements, optimizations, and additional functionalities that could make the class more robust, user-friendly, and integrated with other systems or services. Here's a proposed roadmap: +# kotlin\com\github\simiacryptus\aicoder\config\UsageTable.kt +Creating a feature development roadmap for the `UsageTable` class involves planning out enhancements, optimizations, and additional functionalities that could +make the class more robust, user-friendly, and integrated with other systems or services. Here's a proposed roadmap: #### Phase 1: Core Functionality Enhancements -- **Editable Cells Optimization**: Improve the user experience for editing cells. This could include better validation of input data, auto-completion for certain fields, and undo/redo actions. -- **Dynamic Data Refresh**: Implement a mechanism to automatically refresh the table data at configurable intervals or upon specific events, ensuring the data displayed is always up-to-date. -- **Column Sorting and Filtering**: Allow users to sort data by any column and apply filters to see only the rows that meet certain criteria. +- **Editable Cells Optimization**: Improve the user experience for editing cells. This could include better validation of input data, auto-completion for + certain fields, and undo/redo actions. +- **Dynamic Data Refresh**: Implement a mechanism to automatically refresh the table data at configurable intervals or upon specific events, ensuring the data + displayed is always up-to-date. +- **Column Sorting and Filtering**: Allow users to sort data by any column and apply filters to see only the rows that meet certain criteria. #### Phase 2: User Interface Improvements -- **Custom Cell Rendering**: Enhance the visual representation of table cells based on their values, such as using colors or icons to indicate status or categories. -- **Column Resizing and Reordering**: Enable users to resize and reorder columns according to their preferences, improving the usability of the interface. -- **Advanced Search Functionality**: Introduce a search box to perform text searches across all columns, highlighting matching entries and allowing users to quickly find specific records. +- **Custom Cell Rendering**: Enhance the visual representation of table cells based on their values, such as using colors or icons to indicate status or + categories. +- **Column Resizing and Reordering**: Enable users to resize and reorder columns according to their preferences, improving the usability of the interface. +- **Advanced Search Functionality**: Introduce a search box to perform text searches across all columns, highlighting matching entries and allowing users to + quickly find specific records. #### Phase 3: Performance Optimization -- **Lazy Loading for Large Datasets**: For large usage summaries, implement lazy loading to fetch and display data in chunks as the user scrolls, reducing initial load time and memory usage. -- **Background Data Processing**: Move data processing tasks (e.g., fetching, filtering, sorting) to background threads to keep the UI responsive. +- **Lazy Loading for Large Datasets**: For large usage summaries, implement lazy loading to fetch and display data in chunks as the user scrolls, reducing + initial load time and memory usage. +- **Background Data Processing**: Move data processing tasks (e.g., fetching, filtering, sorting) to background threads to keep the UI responsive. #### Phase 4: Integration and Expansion + - **Export and Import Capabilities**: Allow users to export the table data to CSV, JSON, or Excel formats and import data from these formats into the table. - **Usage Analytics**: Integrate with analytics tools to provide insights into usage patterns, such as most used models, average cost trends, etc. -- **API for External Access**: Develop an API that allows external applications to query and manipulate the usage data, facilitating integration with other systems. - +- **API for External Access**: Develop an API that allows external applications to query and manipulate the usage data, facilitating integration with other + systems. #### Phase 5: Security and Compliance -- **Data Privacy Enhancements**: Ensure that the handling of user data complies with privacy regulations (e.g., GDPR, CCPA). This could involve anonymizing data, providing data access logs, and implementing user consent mechanisms. -- **Role-Based Access Control**: Introduce roles and permissions to restrict access to sensitive data based on the user's role within the organization. +- **Data Privacy Enhancements**: Ensure that the handling of user data complies with privacy regulations (e.g., GDPR, CCPA). This could involve anonymizing + data, providing data access logs, and implementing user consent mechanisms. +- **Role-Based Access Control**: Introduce roles and permissions to restrict access to sensitive data based on the user's role within the organization. #### Phase 6: Documentation and Community -- **Comprehensive Documentation**: Create detailed documentation covering all features, including examples and best practices for extending the `UsageTable` class. -- **Community Engagement**: Establish a community forum or GitHub repository for users to report issues, request features, and contribute to the development of the `UsageTable` class. + +- **Comprehensive Documentation**: Create detailed documentation covering all features, including examples and best practices for extending the `UsageTable` + class. +- **Community Engagement**: Establish a community forum or GitHub repository for users to report issues, request features, and contribute to the development of + the `UsageTable` class. This roadmap is designed to be iterative, allowing for adjustments and additions based on user feedback and technological advancements. # kotlin\com\github\simiacryptus\aicoder\ui\ProjectMenu.kt -Creating a feature development roadmap for the `ProjectMenu` class within the context of an IntelliJ plugin involves planning out the enhancements, fixes, and new capabilities that you intend to introduce to this component over time. Below is a proposed roadmap that outlines potential directions for development, categorized into short-term, mid-term, and long-term goals. - +Creating a feature development roadmap for the `ProjectMenu` class within the context of an IntelliJ plugin involves planning out the enhancements, fixes, and +new capabilities that you intend to introduce to this component over time. Below is a proposed roadmap that outlines potential directions for development, +categorized into short-term, mid-term, and long-term goals. #### Short-Term Goals (1-3 Months) -1. **Enhance UI Responsiveness**: Improve the responsiveness of the project menu actions, ensuring that any action taken by the user is reflected immediately without noticeable lag. +1. **Enhance UI Responsiveness**: Improve the responsiveness of the project menu actions, ensuring that any action taken by the user is reflected immediately + without noticeable lag. -2. **Expand Action Set**: Introduce more file actions into the `AppSettingsState` to provide users with a broader range of functionalities directly from the project menu. +2. **Expand Action Set**: Introduce more file actions into the `AppSettingsState` to provide users with a broader range of functionalities directly from the + project menu. -3. **Improve Error Handling**: Implement more robust error handling within the `getChildren` method to gracefully manage and log unexpected issues, enhancing the overall stability of the plugin. - -4. **User Customization**: Allow users to customize which actions appear in their project menu through a settings panel, giving them control over their workflow. +3. **Improve Error Handling**: Implement more robust error handling within the `getChildren` method to gracefully manage and log unexpected issues, enhancing + the overall stability of the plugin. +4. **User Customization**: Allow users to customize which actions appear in their project menu through a settings panel, giving them control over their + workflow. #### Mid-Term Goals (4-6 Months) -1. **Context-Sensitive Actions**: Develop logic to show or hide certain actions based on the context of the user's selection in the project view. For example, different actions might be shown for directories versus files. - -2. **Performance Optimization**: Profile the plugin's performance, especially when dealing with large projects, and optimize the code to reduce memory usage and speed up action loading times. +1. **Context-Sensitive Actions**: Develop logic to show or hide certain actions based on the context of the user's selection in the project view. For example, + different actions might be shown for directories versus files. -3. **Integration with Other Tools**: Start integrating with other tools and plugins available in the IntelliJ ecosystem to provide a more seamless experience for users working with various technologies. +2. **Performance Optimization**: Profile the plugin's performance, especially when dealing with large projects, and optimize the code to reduce memory usage and + speed up action loading times. -4. **Localization and Accessibility**: Begin localizing the plugin's UI to support multiple languages and improve accessibility features to ensure it is usable by a wider audience. +3. **Integration with Other Tools**: Start integrating with other tools and plugins available in the IntelliJ ecosystem to provide a more seamless experience + for users working with various technologies. +4. **Localization and Accessibility**: Begin localizing the plugin's UI to support multiple languages and improve accessibility features to ensure it is usable + by a wider audience. #### Long-Term Goals (7-12 Months) -1. **Machine Learning-Based Suggestions**: Implement a feature that uses machine learning to suggest the most relevant actions to the user based on their project's context and past actions. +1. **Machine Learning-Based Suggestions**: Implement a feature that uses machine learning to suggest the most relevant actions to the user based on their + project's context and past actions. -2. **Extensive Customization Framework**: Develop a comprehensive framework that allows users to create their own actions and integrate them into the project menu, including a GUI for easy configuration. +2. **Extensive Customization Framework**: Develop a comprehensive framework that allows users to create their own actions and integrate them into the project + menu, including a GUI for easy configuration. -3. **Collaboration Features**: Introduce features that facilitate collaboration among team members directly from the project menu, such as sharing custom actions or configurations. - -4. **Comprehensive Documentation and Tutorials**: Create detailed documentation and tutorials covering all aspects of the plugin, including how to extend its functionalities, to encourage community contributions. +3. **Collaboration Features**: Introduce features that facilitate collaboration among team members directly from the project menu, such as sharing custom + actions or configurations. +4. **Comprehensive Documentation and Tutorials**: Create detailed documentation and tutorials covering all aspects of the plugin, including how to extend its + functionalities, to encourage community contributions. #### Continuous Improvement -- **Feedback Loop**: Establish a mechanism for collecting user feedback and incorporating it into the development process, ensuring that the plugin evolves in alignment with the needs of its users. +- **Feedback Loop**: Establish a mechanism for collecting user feedback and incorporating it into the development process, ensuring that the plugin evolves in + alignment with the needs of its users. -- **Regular Updates**: Commit to a regular release schedule for updates, including new features, bug fixes, and performance improvements, to keep the plugin relevant and useful. +- **Regular Updates**: Commit to a regular release schedule for updates, including new features, bug fixes, and performance improvements, to keep the plugin + relevant and useful. -- **Community Engagement**: Engage with the IntelliJ plugin development community through forums, social media, and conferences to share knowledge, gather insights, and stay informed about best practices. +- **Community Engagement**: Engage with the IntelliJ plugin development community through forums, social media, and conferences to share knowledge, gather + insights, and stay informed about best practices. -This roadmap is a living document and should be revisited and revised regularly based on technological advancements, user feedback, and the evolving landscape of the IntelliJ platform. +This roadmap is a living document and should be revisited and revised regularly based on technological advancements, user feedback, and the evolving landscape +of the IntelliJ platform. # kotlin\com\github\simiacryptus\aicoder\ui\TokenCountWidgetFactory.kt -Developing a feature like the Token Count Widget for an IDE, such as IntelliJ, involves several stages from initial conception to final deployment and maintenance. Below is a detailed roadmap outlining the key phases and steps involved in the development of this feature. - +Developing a feature like the Token Count Widget for an IDE, such as IntelliJ, involves several stages from initial conception to final deployment and +maintenance. Below is a detailed roadmap outlining the key phases and steps involved in the development of this feature. #### 1. Conceptualization and Planning + - **Idea Generation**: Identify the need for a token count widget in the IDE to help developers understand the complexity and size of their code. - **Feasibility Study**: Assess the technical feasibility and the potential impact on the user experience. - **Requirements Gathering**: Define the functional and non-functional requirements for the widget. - **Roadmap Creation**: Outline the development timeline, including milestones and deadlines. - #### 2. Design + - **Architecture Design**: Decide on the widget's architecture, including how it integrates with the IDE and interacts with other components. - **UI/UX Design**: Design the user interface and experience, focusing on how the token count is displayed and updated. -- **Technical Specification**: Document the technical specifications, including the choice of programming languages, libraries (e.g., GPT4Tokenizer for token estimation), and APIs. - +- **Technical Specification**: Document the technical specifications, including the choice of programming languages, libraries (e.g., GPT4Tokenizer for token + estimation), and APIs. #### 3. Development + - **Setup Development Environment**: Prepare the development environment, including IDE setup, project structure, and version control. - **Core Development**: - Implement the widget's main functionality to count tokens in the current file or selection. - Integrate with the IDE to listen for file changes, selection changes, and document edits. - Ensure the widget updates the token count in real-time and displays it in the status bar. -- **Testing and Debugging**: Conduct unit tests, integration tests, and manual testing to ensure the widget works as expected without introducing bugs or performance issues. - +- **Testing and Debugging**: Conduct unit tests, integration tests, and manual testing to ensure the widget works as expected without introducing bugs or + performance issues. #### 4. Deployment + - **Beta Release**: Deploy the widget as a beta version to gather early feedback from a limited user group. - **Feedback Incorporation**: Analyze feedback and make necessary adjustments to the widget's functionality and performance. - **Final Release**: Deploy the final version of the widget to the plugin marketplace for all users. - #### 5. Maintenance and Updates + - **Monitoring**: Continuously monitor the widget's performance and user feedback post-launch. - **Bug Fixes**: Address any reported bugs or issues in a timely manner. - **Feature Updates**: Based on user feedback and technological advancements, periodically release updates to improve the widget or add new features. - #### 6. Marketing and Community Engagement + - **Documentation**: Create comprehensive documentation, including installation guides, user manuals, and FAQs. - **Promotion**: Promote the widget through social media, blogs, and developer forums to increase adoption. - **Community Support**: Engage with the user community to provide support, gather feedback, and discuss potential improvements. -This roadmap provides a structured approach to developing the Token Count Widget, ensuring that the feature is well-designed, functional, and meets the needs of its users. +This roadmap provides a structured approach to developing the Token Count Widget, ensuring that the feature is well-designed, functional, and meets the needs of +its users. # kotlin\com\github\simiacryptus\aicoder\ui\TemperatureControlWidgetFactory.kt -Creating a feature development roadmap for the `TemperatureControlWidgetFactory` and its associated components involves outlining the future enhancements, improvements, and additions planned for this IntelliJ IDEA plugin component. The roadmap will be divided into short-term, mid-term, and long-term goals, each with specific features and improvements to be implemented. - +Creating a feature development roadmap for the `TemperatureControlWidgetFactory` and its associated components involves outlining the future enhancements, +improvements, and additions planned for this IntelliJ IDEA plugin component. The roadmap will be divided into short-term, mid-term, and long-term goals, each +with specific features and improvements to be implemented. #### Short-Term Goals (0-3 Months) -- **Bug Fixes and Stability Improvements**: Address any known bugs and improve the stability of the current implementation. This includes ensuring that the temperature slider accurately reflects changes in the `AppSettingsState` and does not cause any performance issues. -- **UI Enhancements**: Improve the visual appearance of the temperature control slider and the feedback panel. This could involve better alignment, modern UI components, and a more intuitive layout. -- **Documentation and Help**: Develop comprehensive documentation for the widget, including tooltips, help sections, and online resources that users can access directly through the feedback panel. +- **Bug Fixes and Stability Improvements**: Address any known bugs and improve the stability of the current implementation. This includes ensuring that the + temperature slider accurately reflects changes in the `AppSettingsState` and does not cause any performance issues. +- **UI Enhancements**: Improve the visual appearance of the temperature control slider and the feedback panel. This could involve better alignment, modern UI + components, and a more intuitive layout. +- **Documentation and Help**: Develop comprehensive documentation for the widget, including tooltips, help sections, and online resources that users can access + directly through the feedback panel. #### Mid-Term Goals (3-6 Months) -- **Configuration Options**: Add more configuration options to the widget, allowing users to customize its behavior and appearance. This could include settings for slider step size, temperature range, and default values. -- **Performance Optimization**: Optimize the widget's performance, especially when interacting with the IntelliJ IDEA status bar and other components. This may involve asynchronous updates and reducing resource consumption. -- **User Feedback Integration**: Implement a system to collect user feedback directly through the feedback panel and use this feedback to guide future development. This could include feature requests, bug reports, and general suggestions. +- **Configuration Options**: Add more configuration options to the widget, allowing users to customize its behavior and appearance. This could include settings + for slider step size, temperature range, and default values. +- **Performance Optimization**: Optimize the widget's performance, especially when interacting with the IntelliJ IDEA status bar and other components. This may + involve asynchronous updates and reducing resource consumption. +- **User Feedback Integration**: Implement a system to collect user feedback directly through the feedback panel and use this feedback to guide future + development. This could include feature requests, bug reports, and general suggestions. #### Long-Term Goals (6-12 Months) -- **Advanced Temperature Control Features**: Introduce advanced features for the temperature control, such as presets for different coding scenarios, AI suggestions based on the current temperature setting, and integration with other AI coding assistant features. -- **Internationalization and Localization**: Make the widget available in multiple languages, catering to a global user base. This involves translating UI elements and providing localized support resources. -- **Community and Ecosystem Development**: Foster a community around the widget by encouraging third-party contributions, developing plugins or extensions, and integrating with other tools and services used by developers. +- **Advanced Temperature Control Features**: Introduce advanced features for the temperature control, such as presets for different coding scenarios, AI + suggestions based on the current temperature setting, and integration with other AI coding assistant features. +- **Internationalization and Localization**: Make the widget available in multiple languages, catering to a global user base. This involves translating UI + elements and providing localized support resources. +- **Community and Ecosystem Development**: Foster a community around the widget by encouraging third-party contributions, developing plugins or extensions, and + integrating with other tools and services used by developers. #### Continuous Goals -- **User Experience (UX) Improvements**: Continuously seek to improve the user experience based on user feedback and usability testing. This includes refining the UI, enhancing accessibility, and simplifying workflows. -- **Compatibility and Integration Testing**: Regularly test the widget with different versions of IntelliJ IDEA and other JetBrains IDEs to ensure compatibility. Also, explore integration possibilities with other plugins and tools commonly used by developers. -- **Security and Privacy**: Ensure that the widget adheres to best practices for security and privacy, especially when handling user data and interactions with external services. -This roadmap provides a structured approach to developing the `TemperatureControlWidgetFactory` and its components, focusing on delivering value to users while continuously improving and expanding its capabilities. +- **User Experience (UX) Improvements**: Continuously seek to improve the user experience based on user feedback and usability testing. This includes refining + the UI, enhancing accessibility, and simplifying workflows. +- **Compatibility and Integration Testing**: Regularly test the widget with different versions of IntelliJ IDEA and other JetBrains IDEs to ensure + compatibility. Also, explore integration possibilities with other plugins and tools commonly used by developers. +- **Security and Privacy**: Ensure that the widget adheres to best practices for security and privacy, especially when handling user data and interactions with + external services. -# kotlin\com\github\simiacryptus\aicoder\util\CodeChatSocketManager.kt +This roadmap provides a structured approach to developing the `TemperatureControlWidgetFactory` and its components, focusing on delivering value to users while +continuously improving and expanding its capabilities. -The `CodeChatSocketManager` class is a specialized extension of `ChatSocketManager` designed to facilitate coding assistance through an AI-powered chat interface. It integrates with OpenAI's models to provide real-time coding help within a specific context, such as a file or a snippet of code. Below is a feature development roadmap to enhance the capabilities of the `CodeChatSocketManager` and improve the user experience. +# kotlin\com\github\simiacryptus\aicoder\util\CodeChatSocketManager.kt +The `CodeChatSocketManager` class is a specialized extension of `ChatSocketManager` designed to facilitate coding assistance through an AI-powered chat +interface. It integrates with OpenAI's models to provide real-time coding help within a specific context, such as a file or a snippet of code. Below is a +feature development roadmap to enhance the capabilities of the `CodeChatSocketManager` and improve the user experience. #### Phase 1: Core Functionality Enhancements -- **Contextual Understanding Improvement**: Enhance the AI's ability to understand the context of the code snippet better, including the programming language nuances, libraries used, and the overall purpose of the code. -- **Response Accuracy**: Improve the accuracy of the AI responses to user queries, ensuring that the advice is not only syntactically correct but also logically sound and best practice-oriented. -- **Multi-Language Support**: Expand the range of programming languages supported by the `CodeChatSocketManager`, catering to a broader audience of developers. +- **Contextual Understanding Improvement**: Enhance the AI's ability to understand the context of the code snippet better, including the programming language + nuances, libraries used, and the overall purpose of the code. +- **Response Accuracy**: Improve the accuracy of the AI responses to user queries, ensuring that the advice is not only syntactically correct but also logically + sound and best practice-oriented. +- **Multi-Language Support**: Expand the range of programming languages supported by the `CodeChatSocketManager`, catering to a broader audience of developers. #### Phase 2: User Experience Improvements -- **Interactive Code Editing**: Implement an interactive code editor within the chat interface, allowing users to edit code snippets in real-time and receive immediate feedback from the AI. -- **Personalization**: Introduce user profiles that remember past interactions, preferred programming languages, and common coding issues faced by the user, allowing for more personalized assistance. -- **Real-Time Collaboration**: Enable real-time collaboration features, allowing multiple users to work on the same piece of code simultaneously with AI assistance. +- **Interactive Code Editing**: Implement an interactive code editor within the chat interface, allowing users to edit code snippets in real-time and receive + immediate feedback from the AI. +- **Personalization**: Introduce user profiles that remember past interactions, preferred programming languages, and common coding issues faced by the user, + allowing for more personalized assistance. +- **Real-Time Collaboration**: Enable real-time collaboration features, allowing multiple users to work on the same piece of code simultaneously with AI + assistance. #### Phase 3: Advanced Features -- **Code Refactoring Suggestions**: Develop the AI's capability to suggest code refactoring options, helping users improve code quality, readability, and performance. -- **Bug Detection and Suggestions**: Implement advanced bug detection algorithms that not only identify potential issues in the code but also suggest fixes. -- **Integration with Development Environments**: Create plugins for popular Integrated Development Environments (IDEs) and code editors, allowing developers to use `CodeChatSocketManager`'s features directly within their preferred coding environment. +- **Code Refactoring Suggestions**: Develop the AI's capability to suggest code refactoring options, helping users improve code quality, readability, and + performance. +- **Bug Detection and Suggestions**: Implement advanced bug detection algorithms that not only identify potential issues in the code but also suggest fixes. +- **Integration with Development Environments**: Create plugins for popular Integrated Development Environments (IDEs) and code editors, allowing developers to + use `CodeChatSocketManager`'s features directly within their preferred coding environment. #### Phase 4: Community and Sharing -- **Shared Code Snippets Library**: Build a library of common code snippets and solutions contributed by the community, allowing users to search for and use snippets in their projects. -- **User Contribution Rewards**: Introduce a rewards system for users who contribute valuable code snippets, solutions, or assist other users, fostering a supportive community environment. -- **Live Coding Sessions**: Host live coding sessions where users can join to code together on a project with real-time AI assistance and peer support. +- **Shared Code Snippets Library**: Build a library of common code snippets and solutions contributed by the community, allowing users to search for and use + snippets in their projects. +- **User Contribution Rewards**: Introduce a rewards system for users who contribute valuable code snippets, solutions, or assist other users, fostering a + supportive community environment. +- **Live Coding Sessions**: Host live coding sessions where users can join to code together on a project with real-time AI assistance and peer support. #### Phase 5: Security and Privacy Enhancements -- **Secure Coding Practices**: Incorporate secure coding practices into the AI's suggestions, ensuring that the code complies with security standards and best practices. + +- **Secure Coding Practices**: Incorporate secure coding practices into the AI's suggestions, ensuring that the code complies with security standards and best + practices. - **Privacy Controls**: Implement robust privacy controls, allowing users to manage who can see their code, questions, and interactions with the AI. - **Audit Trails**: Create detailed audit trails for all interactions, ensuring transparency and accountability for actions taken within the platform. -This roadmap outlines a comprehensive strategy for developing the `CodeChatSocketManager` into a more powerful, user-friendly, and community-oriented platform for coding assistance. Each phase builds upon the previous one, gradually introducing new features and improvements based on user feedback and technological advancements. +This roadmap outlines a comprehensive strategy for developing the `CodeChatSocketManager` into a more powerful, user-friendly, and community-oriented platform +for coding assistance. Each phase builds upon the previous one, gradually introducing new features and improvements based on user feedback and technological +advancements. # kotlin\com\github\simiacryptus\aicoder\util\ComputerLanguage.kt -The code provided outlines an enumeration `ComputerLanguage` within a Kotlin package, designed to manage different programming languages and their commenting styles, including documentation styles, line comments, block comments, and file extensions. This setup is particularly useful for applications that need to generate, analyze, or modify code across various programming languages, such as IDEs, code analysis tools, or documentation generators. - +The code provided outlines an enumeration `ComputerLanguage` within a Kotlin package, designed to manage different programming languages and their commenting +styles, including documentation styles, line comments, block comments, and file extensions. This setup is particularly useful for applications that need to +generate, analyze, or modify code across various programming languages, such as IDEs, code analysis tools, or documentation generators. #### Feature Development Roadmap - ##### Phase 1: Core Functionality Enhancement -- **Refinement of Language Configurations**: Enhance the configuration options for each language to include more detailed settings, such as indentation styles, naming conventions, and code formatting rules. -- **Dynamic Configuration Loading**: Implement functionality to load language configurations from external files (e.g., JSON or XML), allowing users to add support for new languages or modify existing configurations without altering the source code. +- **Refinement of Language Configurations**: Enhance the configuration options for each language to include more detailed settings, such as indentation styles, + naming conventions, and code formatting rules. +- **Dynamic Configuration Loading**: Implement functionality to load language configurations from external files (e.g., JSON or XML), allowing users to add + support for new languages or modify existing configurations without altering the source code. ##### Phase 2: Integration and Usability Improvements -- **Plugin System for IDEs**: Develop plugins for popular IDEs (e.g., IntelliJ IDEA, Visual Studio Code) that utilize the `ComputerLanguage` enumeration to provide enhanced code commenting and documentation features. -- **GUI Configuration Editor**: Create a graphical interface for editing and managing language configurations, making it easier for users to customize language settings without directly manipulating configuration files. +- **Plugin System for IDEs**: Develop plugins for popular IDEs (e.g., IntelliJ IDEA, Visual Studio Code) that utilize the `ComputerLanguage` enumeration to + provide enhanced code commenting and documentation features. +- **GUI Configuration Editor**: Create a graphical interface for editing and managing language configurations, making it easier for users to customize language + settings without directly manipulating configuration files. ##### Phase 3: Advanced Features and Extensions -- **Code Analysis and Refactoring Tools**: Leverage the language configurations to build tools for code analysis, highlighting potential issues or inconsistencies in comments and documentation. Include features for automatic refactoring of comments to adhere to specified styles. -- **Documentation Generation**: Implement a documentation generator that can parse source code in supported languages and produce comprehensive documentation based on doc comments, with support for various output formats (e.g., HTML, PDF). +- **Code Analysis and Refactoring Tools**: Leverage the language configurations to build tools for code analysis, highlighting potential issues or + inconsistencies in comments and documentation. Include features for automatic refactoring of comments to adhere to specified styles. +- **Documentation Generation**: Implement a documentation generator that can parse source code in supported languages and produce comprehensive documentation + based on doc comments, with support for various output formats (e.g., HTML, PDF). ##### Phase 4: Community and Ecosystem Development -- **Community Contributions**: Establish a platform for the community to contribute configurations for additional languages, share custom configurations, and collaborate on the development of new features. -- **Integration with Other Tools**: Work on integrations with code quality tools, version control systems, and continuous integration pipelines, allowing for automated checks and corrections of code comments and documentation as part of the development workflow. +- **Community Contributions**: Establish a platform for the community to contribute configurations for additional languages, share custom configurations, and + collaborate on the development of new features. +- **Integration with Other Tools**: Work on integrations with code quality tools, version control systems, and continuous integration pipelines, allowing for + automated checks and corrections of code comments and documentation as part of the development workflow. ##### Phase 5: Machine Learning and AI Enhancements -- **AI-Based Comment Generation**: Integrate machine learning models to automatically generate meaningful comments and documentation based on code analysis, reducing the manual effort required for documenting code. -- **Natural Language Processing (NLP) for Code**: Utilize NLP techniques to improve the understanding of code and comments, enabling features like automatic translation of comments between languages and detection of discrepancies between code and its documentation. +- **AI-Based Comment Generation**: Integrate machine learning models to automatically generate meaningful comments and documentation based on code analysis, + reducing the manual effort required for documenting code. +- **Natural Language Processing (NLP) for Code**: Utilize NLP techniques to improve the understanding of code and comments, enabling features like automatic + translation of comments between languages and detection of discrepancies between code and its documentation. #### Conclusion -The roadmap outlines a comprehensive plan to evolve the `ComputerLanguage` enumeration into a versatile toolset for managing code comments and documentation across multiple programming languages. By focusing on core functionality, usability, advanced features, community involvement, and leveraging AI, the project aims to significantly improve the developer experience and code quality in software projects. -# kotlin\com\github\simiacryptus\aicoder\util\BlockComment.kt +The roadmap outlines a comprehensive plan to evolve the `ComputerLanguage` enumeration into a versatile toolset for managing code comments and documentation +across multiple programming languages. By focusing on core functionality, usability, advanced features, community involvement, and leveraging AI, the project +aims to significantly improve the developer experience and code quality in software projects. +# kotlin\com\github\simiacryptus\aicoder\util\BlockComment.kt #### Feature Development Roadmap for BlockComment Utility -The `BlockComment` utility is designed to facilitate the creation, manipulation, and formatting of block comments in code. This roadmap outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. - +The `BlockComment` utility is designed to facilitate the creation, manipulation, and formatting of block comments in code. This roadmap outlines the planned +features and improvements to enhance its functionality, usability, and integration capabilities. ##### Phase 1: Core Functionality Enhancements -1. **Customizable Delimiters**: Extend the `Factory` class to support customizable delimiters for comments, allowing users to define their own start and end markers for block comments. - -2. **Whitespace Normalization**: Implement a feature to normalize the amount of whitespace within comments, ensuring consistent formatting across different blocks. +1. **Customizable Delimiters**: Extend the `Factory` class to support customizable delimiters for comments, allowing users to define their own start and end + markers for block comments. -3. **Support for Inline Comments**: Introduce the ability to convert block comments to inline comments and vice versa, providing flexibility in how comments are presented. +2. **Whitespace Normalization**: Implement a feature to normalize the amount of whitespace within comments, ensuring consistent formatting across different + blocks. -4. **Encoding and Decoding**: Develop methods to encode special characters within comments to ensure they are safely included without breaking the code and to decode them back when displaying or editing. +3. **Support for Inline Comments**: Introduce the ability to convert block comments to inline comments and vice versa, providing flexibility in how comments are + presented. +4. **Encoding and Decoding**: Develop methods to encode special characters within comments to ensure they are safely included without breaking the code and to + decode them back when displaying or editing. ##### Phase 2: Usability Improvements @@ -2121,483 +2670,608 @@ The `BlockComment` utility is designed to facilitate the creation, manipulation, 6. **Syntax Highlighting**: Integrate syntax highlighting within the comment editor to improve readability, especially for code snippets included in comments. -7. **Comment Templates**: Introduce predefined templates for common comment structures, such as TODOs, FIXMEs, and documentation headers, to streamline the creation process. +7. **Comment Templates**: Introduce predefined templates for common comment structures, such as TODOs, FIXMEs, and documentation headers, to streamline the + creation process. 8. **Bulk Comment Management**: Develop tools for managing comments in bulk, including batch editing, deletion, and conversion between comment types. - ##### Phase 3: Integration and Compatibility -9. **IDE Integration**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code to allow direct manipulation of block comments within the IDE. - -10. **Version Control System Compatibility**: Ensure that comments are preserved and properly managed during merge conflicts and other version control operations. +9. **IDE Integration**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code to allow + direct manipulation of block comments within the IDE. -11. **Language Agnosticism**: Enhance the utility to support multiple programming languages, automatically adapting comment syntax based on the language of the source code. +10. **Version Control System Compatibility**: Ensure that comments are preserved and properly managed during merge conflicts and other version control + operations. -12. **API Exposure**: Expose a well-documented API for the `BlockComment` utility, enabling third-party developers to integrate its functionality into their own tools and applications. +11. **Language Agnosticism**: Enhance the utility to support multiple programming languages, automatically adapting comment syntax based on the language of the + source code. +12. **API Exposure**: Expose a well-documented API for the `BlockComment` utility, enabling third-party developers to integrate its functionality into their own + tools and applications. ##### Phase 4: Advanced Features -13. **Comment Analytics**: Implement analytics features to track comment density, quality, and coverage across codebases, providing insights into documentation practices. +13. **Comment Analytics**: Implement analytics features to track comment density, quality, and coverage across codebases, providing insights into documentation + practices. -14. **Automated Comment Generation**: Explore the integration of natural language processing (NLP) techniques to automatically generate meaningful comments based on code analysis. +14. **Automated Comment Generation**: Explore the integration of natural language processing (NLP) techniques to automatically generate meaningful comments + based on code analysis. -15. **Collaborative Commenting**: Develop features to support collaborative commenting, allowing multiple users to contribute to and discuss comments in a shared environment. - -16. **Export and Import Comments**: Allow users to export comments to external files and import them back, facilitating documentation sharing and review processes outside the codebase. +15. **Collaborative Commenting**: Develop features to support collaborative commenting, allowing multiple users to contribute to and discuss comments in a + shared environment. +16. **Export and Import Comments**: Allow users to export comments to external files and import them back, facilitating documentation sharing and review + processes outside the codebase. ##### Conclusion -The development roadmap for the `BlockComment` utility aims to significantly enhance its functionality, making it a versatile tool for managing comments in code. By focusing on core enhancements, usability improvements, integration capabilities, and advanced features, the utility will cater to a wide range of needs, from individual developers to large development teams. +The development roadmap for the `BlockComment` utility aims to significantly enhance its functionality, making it a versatile tool for managing comments in +code. By focusing on core enhancements, usability improvements, integration capabilities, and advanced features, the utility will cater to a wide range of +needs, from individual developers to large development teams. # kotlin\com\github\simiacryptus\aicoder\util\IdeaKotlinInterpreter.kt -The `IdeaKotlinInterpreter` class is a specialized Kotlin interpreter designed to work within the IntelliJ IDEA environment, leveraging the Kotlin scripting capabilities. This class extends a generic `KotlinInterpreter` by adding IntelliJ IDEA-specific functionalities, such as project context awareness and enhanced script execution capabilities. Below is a proposed feature development roadmap to enhance the `IdeaKotlinInterpreter` class further, making it more robust, user-friendly, and integrated with the IntelliJ IDEA ecosystem. - +The `IdeaKotlinInterpreter` class is a specialized Kotlin interpreter designed to work within the IntelliJ IDEA environment, leveraging the Kotlin scripting +capabilities. This class extends a generic `KotlinInterpreter` by adding IntelliJ IDEA-specific functionalities, such as project context awareness and enhanced +script execution capabilities. Below is a proposed feature development roadmap to enhance the `IdeaKotlinInterpreter` class further, making it more robust, +user-friendly, and integrated with the IntelliJ IDEA ecosystem. #### Phase 1: Core Enhancements -- **Improved Script Execution Performance**: Optimize the script engine initialization and execution process to reduce latency and improve performance for executing Kotlin scripts. -- **Dynamic Symbol Resolution**: Enhance the symbol resolution mechanism to dynamically resolve symbols at runtime, allowing for more flexible and powerful script execution scenarios. -- **Error Handling and Logging**: Implement a comprehensive error handling and logging framework to capture and report script execution errors, making debugging easier for developers. +- **Improved Script Execution Performance**: Optimize the script engine initialization and execution process to reduce latency and improve performance for + executing Kotlin scripts. +- **Dynamic Symbol Resolution**: Enhance the symbol resolution mechanism to dynamically resolve symbols at runtime, allowing for more flexible and powerful + script execution scenarios. +- **Error Handling and Logging**: Implement a comprehensive error handling and logging framework to capture and report script execution errors, making debugging + easier for developers. #### Phase 2: IDE Integration -- **Project Context Awareness**: Enhance the interpreter to be more aware of the IntelliJ IDEA project context, allowing it to access and manipulate project files, configurations, and other resources directly from the scripts. -- **Debugging Support**: Integrate with the IntelliJ IDEA debugging facilities, enabling breakpoints, step-through debugging, and variable inspection for scripts executed by the interpreter. -- **Code Completion and Inspection**: Leverage IntelliJ IDEA's code completion and inspection capabilities within the scripting environment, providing a seamless development experience. +- **Project Context Awareness**: Enhance the interpreter to be more aware of the IntelliJ IDEA project context, allowing it to access and manipulate project + files, configurations, and other resources directly from the scripts. +- **Debugging Support**: Integrate with the IntelliJ IDEA debugging facilities, enabling breakpoints, step-through debugging, and variable inspection for + scripts executed by the interpreter. +- **Code Completion and Inspection**: Leverage IntelliJ IDEA's code completion and inspection capabilities within the scripting environment, providing a + seamless development experience. #### Phase 3: Extensibility and Plugins -- **Extension Points**: Define extension points in the interpreter, allowing third-party plugins to extend its functionality, such as adding new symbol providers, custom script commands, or integration with other tools and services. -- **Script Libraries and Templates**: Develop a library of reusable script templates and libraries that can be easily imported and used within scripts, speeding up development and promoting best practices. -- **Integration with External Tools**: Provide built-in support for integrating with external tools and services, such as version control systems, build tools, and cloud services, directly from the scripts. +- **Extension Points**: Define extension points in the interpreter, allowing third-party plugins to extend its functionality, such as adding new symbol + providers, custom script commands, or integration with other tools and services. +- **Script Libraries and Templates**: Develop a library of reusable script templates and libraries that can be easily imported and used within scripts, speeding + up development and promoting best practices. +- **Integration with External Tools**: Provide built-in support for integrating with external tools and services, such as version control systems, build tools, + and cloud services, directly from the scripts. #### Phase 4: User Experience and Documentation -- **Interactive Script Console**: Implement an interactive script console within IntelliJ IDEA, allowing developers to write, execute, and test scripts in real-time. -- **Comprehensive Documentation**: Create comprehensive documentation covering all aspects of the interpreter, including setup, usage examples, best practices, and troubleshooting guides. -- **Tutorials and Sample Projects**: Provide a set of tutorials and sample projects demonstrating how to effectively use the interpreter for various tasks and projects. +- **Interactive Script Console**: Implement an interactive script console within IntelliJ IDEA, allowing developers to write, execute, and test scripts in + real-time. +- **Comprehensive Documentation**: Create comprehensive documentation covering all aspects of the interpreter, including setup, usage examples, best practices, + and troubleshooting guides. +- **Tutorials and Sample Projects**: Provide a set of tutorials and sample projects demonstrating how to effectively use the interpreter for various tasks and + projects. #### Phase 5: Community and Feedback + - **Community Engagement**: Establish a community forum or platform for users of the interpreter to share scripts, ask questions, and collaborate on projects. -- **Feedback Loop**: Implement a feedback mechanism within the interpreter or the IntelliJ IDEA plugin to collect user feedback, bug reports, and feature requests, guiding future development priorities. +- **Feedback Loop**: Implement a feedback mechanism within the interpreter or the IntelliJ IDEA plugin to collect user feedback, bug reports, and feature + requests, guiding future development priorities. -This roadmap aims to evolve the `IdeaKotlinInterpreter` into a powerful, flexible, and user-friendly tool for Kotlin scripting within the IntelliJ IDEA ecosystem, catering to the needs of developers, scriptwriters, and plugin authors alike. +This roadmap aims to evolve the `IdeaKotlinInterpreter` into a powerful, flexible, and user-friendly tool for Kotlin scripting within the IntelliJ IDEA +ecosystem, catering to the needs of developers, scriptwriters, and plugin authors alike. # kotlin\com\github\simiacryptus\aicoder\util\IdeaOpenAIClient.kt -Developing a feature for a software project, such as enhancing the `IdeaOpenAIClient` class in a plugin for IntelliJ IDEA, involves a series of steps from initial planning to final deployment and feedback collection. Below is a structured roadmap for developing a new feature within this context: - +Developing a feature for a software project, such as enhancing the `IdeaOpenAIClient` class in a plugin for IntelliJ IDEA, involves a series of steps from +initial planning to final deployment and feedback collection. Below is a structured roadmap for developing a new feature within this context: #### 1. Conceptualization and Planning (1-2 Weeks) + - **Idea Generation:** Brainstorm potential features that could enhance the `IdeaOpenAIClient`, focusing on user needs and plugin functionality. - **Feasibility Study:** Assess the technical feasibility, resource requirements, and potential impact of the proposed features. - **Feature Selection:** Choose the most valuable feature to develop based on the feasibility study and potential impact. - **Requirement Gathering:** Define detailed functional and non-functional requirements for the selected feature. - #### 2. Design Phase (2-3 Weeks) + - **Technical Specification:** Create a detailed technical design document outlining the architecture, data flow, and integration points of the feature. - **UI/UX Design:** If the feature involves UI changes, design the user interface and experience with mockups and user flow diagrams. - **Review and Approval:** Present the design documents to stakeholders for feedback and approval. - #### 3. Development Phase (4-6 Weeks) + - **Environment Setup:** Prepare the development environment, including necessary tools, libraries, and access rights. -- **Coding:** Implement the feature according to the technical specifications. For `IdeaOpenAIClient`, this might involve adding new methods, modifying existing ones, and ensuring compatibility with the IntelliJ platform. +- **Coding:** Implement the feature according to the technical specifications. For `IdeaOpenAIClient`, this might involve adding new methods, modifying existing + ones, and ensuring compatibility with the IntelliJ platform. - **Code Review:** Conduct regular code reviews to ensure code quality, adherence to standards, and to catch potential issues early. - #### 4. Testing Phase (2-3 Weeks) + - **Unit Testing:** Write and execute unit tests to cover the new feature's functionality, ensuring it works as expected in isolation. - **Integration Testing:** Test the feature in the context of the entire plugin to ensure it integrates smoothly without causing regressions. - **User Acceptance Testing (UAT):** Allow a select group of end-users to test the new feature and collect feedback on its usability and functionality. - #### 5. Deployment Phase (1 Week) + - **Pre-Deployment Checklist:** Ensure all pre-deployment activities, such as final code review, testing sign-off, and documentation, are complete. -- **Release:** Deploy the new feature as part of a new version of the plugin. This might involve submitting the plugin to the JetBrains Marketplace and updating the plugin documentation. +- **Release:** Deploy the new feature as part of a new version of the plugin. This might involve submitting the plugin to the JetBrains Marketplace and updating + the plugin documentation. - **Monitoring:** Closely monitor the feature for any issues or unexpected behavior following the release. - #### 6. Post-Deployment (Ongoing) + - **Feedback Collection:** Collect and analyze user feedback on the new feature to understand its impact and any areas for improvement. - **Performance Monitoring:** Monitor the feature's performance and any impact it may have on the overall plugin performance. - **Iterative Improvement:** Based on feedback and performance data, make necessary adjustments or improvements to the feature. - #### 7. Documentation and Knowledge Sharing (Ongoing) + - **Documentation:** Update the project and user documentation to reflect the new feature and any changes to existing functionality. -- **Knowledge Sharing:** Share insights and learnings from the development process with the team and stakeholders, potentially through a post-mortem analysis or a knowledge-sharing session. +- **Knowledge Sharing:** Share insights and learnings from the development process with the team and stakeholders, potentially through a post-mortem analysis or + a knowledge-sharing session. -This roadmap provides a structured approach to feature development, ensuring thorough planning, execution, and evaluation. Adjustments may be necessary based on project size, complexity, and specific requirements. +This roadmap provides a structured approach to feature development, ensuring thorough planning, execution, and evaluation. Adjustments may be necessary based on +project size, complexity, and specific requirements. # kotlin\com\github\simiacryptus\aicoder\util\DiffMatchPatch.kt -Creating a feature development roadmap involves outlining the path from the current state of your project to its future state, with all the features you plan to implement. This roadmap should align with your project's goals, user needs, and business objectives. Here's a step-by-step guide to help you create a comprehensive feature development roadmap: - +Creating a feature development roadmap involves outlining the path from the current state of your project to its future state, with all the features you plan to +implement. This roadmap should align with your project's goals, user needs, and business objectives. Here's a step-by-step guide to help you create a +comprehensive feature development roadmap: #### 1. Define Your Vision and Objectives + - **Vision Statement**: Define what you want to achieve with your project in the long term. - **Objectives**: List specific, measurable objectives that support your vision. - #### 2. Gather and Prioritize Ideas -- **Idea Collection**: Gather feature ideas from stakeholders, including customers, team members, and management. -- **Prioritization**: Use a framework like MoSCoW (Must have, Should have, Could have, Won't have this time) or the RICE scoring model (Reach, Impact, Confidence, Effort) to prioritize features based on value, impact, and feasibility. +- **Idea Collection**: Gather feature ideas from stakeholders, including customers, team members, and management. +- **Prioritization**: Use a framework like MoSCoW (Must have, Should have, Could have, Won't have this time) or the RICE scoring model (Reach, Impact, + Confidence, Effort) to prioritize features based on value, impact, and feasibility. #### 3. Conduct User Research + - **User Surveys and Interviews**: Collect feedback to understand user needs and pain points. - **Persona Development**: Create user personas to represent your target users and their needs. - #### 4. Define Key Features + - **Feature List**: Based on your objectives and user research, define a list of key features that will be developed. - **Feature Descriptions**: Provide detailed descriptions for each feature, including user stories and acceptance criteria. - #### 5. Set Milestones and Timelines + - **Milestones**: Break down the development process into major milestones, each representing a significant phase or the completion of a key feature. - **Timelines**: Assign tentative timelines to each milestone, taking into consideration dependencies and resource availability. - #### 6. Allocate Resources + - **Team Assignments**: Assign team members to specific features or milestones based on their skills and experience. - **Budgeting**: Allocate budget for resources, tools, and any external services required for development. - #### 7. Plan for Risks and Contingencies + - **Risk Assessment**: Identify potential risks that could impact your roadmap and plan mitigation strategies. - **Contingency Planning**: Develop contingency plans for critical risks to ensure project continuity. - #### 8. Communicate the Roadmap + - **Internal Sharing**: Share the roadmap with your team and stakeholders to ensure everyone is aligned and understands their roles. - **External Sharing (if applicable)**: Share a version of the roadmap with customers or users to build anticipation and gather feedback. - #### 9. Review and Update Regularly + - **Regular Reviews**: Schedule regular roadmap reviews to assess progress, discuss challenges, and make adjustments as needed. - **Flexibility**: Be prepared to pivot or reprioritize features based on feedback, new opportunities, or changes in the market. - #### 10. Measure Success + - **KPIs and Metrics**: Define key performance indicators (KPIs) and metrics to measure the success of each feature post-launch. - **Feedback Loops**: Implement feedback loops to continuously collect user feedback and inform future development. -Creating a feature development roadmap is an iterative process that requires flexibility and ongoing communication with your team and stakeholders. By following these steps, you can ensure that your project remains focused, efficient, and aligned with your overall vision and objectives. +Creating a feature development roadmap is an iterative process that requires flexibility and ongoing communication with your team and stakeholders. By following +these steps, you can ensure that your project remains focused, efficient, and aligned with your overall vision and objectives. # kotlin\com\github\simiacryptus\aicoder\util\LineComment.kt -The `LineComment` class and its nested `Factory` class, as part of the `com.github.simiacryptus.aicoder.util` package, provide a structured way to handle line comments within text blocks, particularly useful in the context of code generation or analysis. The development roadmap for enhancing these classes and their functionalities can be structured into several phases, focusing on improving usability, flexibility, and integration capabilities. - +The `LineComment` class and its nested `Factory` class, as part of the `com.simiacryptus.aicoder.util` package, provide a structured way to handle line comments +within text blocks, particularly useful in the context of code generation or analysis. The development roadmap for enhancing these classes and their +functionalities can be structured into several phases, focusing on improving usability, flexibility, and integration capabilities. #### Phase 1: Core Functionality Enhancements -- **Refinement of Comment Handling**: Improve the parsing and generation of comments to handle edge cases more gracefully, such as comments within strings or comments following code on the same line. -- **Support for Different Comment Styles**: Extend the `LineComment` class to support various comment styles (e.g., `//`, `#`, `/* */` for block comments) dynamically based on the programming language in context. -- **Performance Optimization**: Optimize the underlying algorithms for string manipulation and stream processing to enhance performance, especially for large text blocks. - +- **Refinement of Comment Handling**: Improve the parsing and generation of comments to handle edge cases more gracefully, such as comments within strings or + comments following code on the same line. +- **Support for Different Comment Styles**: Extend the `LineComment` class to support various comment styles (e.g., `//`, `#`, `/* */` for block comments) + dynamically based on the programming language in context. +- **Performance Optimization**: Optimize the underlying algorithms for string manipulation and stream processing to enhance performance, especially for large + text blocks. #### Phase 2: Usability Improvements -- **API Documentation**: Comprehensive documentation of all public methods and classes, including examples of common use cases, to make the library more accessible to new users. +- **API Documentation**: Comprehensive documentation of all public methods and classes, including examples of common use cases, to make the library more + accessible to new users. - **Error Handling and Validation**: Implement robust error handling and input validation to provide clear feedback to users when incorrect inputs are provided. -- **Configuration Options**: Introduce configuration options for common settings, such as tab size and default indent style, allowing users to customize the behavior according to their preferences. - +- **Configuration Options**: Introduce configuration options for common settings, such as tab size and default indent style, allowing users to customize the + behavior according to their preferences. #### Phase 3: Advanced Features -- **Integration with Code Formatters**: Develop plugins or integrations with popular code formatters and IDEs to automatically apply `LineComment` functionalities during code formatting. -- **Support for Multiline Comments**: Enhance the `LineComment` class to support the generation and parsing of multiline comments, maintaining the correct indentation and alignment. -- **Annotation Support**: Implement functionality to recognize and handle annotations or special comment tags, enabling users to mark sections of code or comments for specific processing or documentation purposes. - +- **Integration with Code Formatters**: Develop plugins or integrations with popular code formatters and IDEs to automatically apply `LineComment` + functionalities during code formatting. +- **Support for Multiline Comments**: Enhance the `LineComment` class to support the generation and parsing of multiline comments, maintaining the correct + indentation and alignment. +- **Annotation Support**: Implement functionality to recognize and handle annotations or special comment tags, enabling users to mark sections of code or + comments for specific processing or documentation purposes. #### Phase 4: Community and Ecosystem -- **Open Source Contributions**: Encourage community contributions by setting up a clear contribution guide, issue templates, and a responsive process for handling pull requests. -- **Extension Mechanism**: Design an extension mechanism that allows third-party developers to create plugins or add-ons, extending the core functionalities with custom comment styles, formatters, or integrations. -- **Comprehensive Test Suite**: Develop a comprehensive test suite covering a wide range of use cases and edge cases, ensuring the reliability and stability of the library across updates. - +- **Open Source Contributions**: Encourage community contributions by setting up a clear contribution guide, issue templates, and a responsive process for + handling pull requests. +- **Extension Mechanism**: Design an extension mechanism that allows third-party developers to create plugins or add-ons, extending the core functionalities + with custom comment styles, formatters, or integrations. +- **Comprehensive Test Suite**: Develop a comprehensive test suite covering a wide range of use cases and edge cases, ensuring the reliability and stability of + the library across updates. #### Phase 5: Long-Term Vision -- **Language-Agnostic Architecture**: Evolve the library towards a more language-agnostic architecture, enabling support for a broader range of programming languages without significant modifications to the core logic. -- **Machine Learning Integration**: Explore the integration of machine learning models for intelligent comment generation and code documentation, leveraging natural language processing techniques. -- **Community-Driven Language Support**: Foster a community-driven approach to adding support for new languages and comment styles, including documentation and examples contributed by users. +- **Language-Agnostic Architecture**: Evolve the library towards a more language-agnostic architecture, enabling support for a broader range of programming + languages without significant modifications to the core logic. +- **Machine Learning Integration**: Explore the integration of machine learning models for intelligent comment generation and code documentation, leveraging + natural language processing techniques. +- **Community-Driven Language Support**: Foster a community-driven approach to adding support for new languages and comment styles, including documentation and + examples contributed by users. -This roadmap outlines a strategic approach to developing the `LineComment` class and its ecosystem, aiming to create a versatile and powerful tool for code generation, analysis, and documentation tasks. +This roadmap outlines a strategic approach to developing the `LineComment` class and its ecosystem, aiming to create a versatile and powerful tool for code +generation, analysis, and documentation tasks. # kotlin\com\github\simiacryptus\aicoder\util\psi\PsiClassContext.kt -Creating a feature development roadmap for the `PsiClassContext` class and its associated functionalities involves outlining a series of enhancements, optimizations, and new features that can be developed over time. This roadmap aims to improve the utility, performance, and user experience of working with PSI (Program Structure Interface) elements in IntelliJ-based IDEs for various programming languages. The roadmap is divided into short-term, mid-term, and long-term goals. - +Creating a feature development roadmap for the `PsiClassContext` class and its associated functionalities involves outlining a series of enhancements, +optimizations, and new features that can be developed over time. This roadmap aims to improve the utility, performance, and user experience of working with +PSI (Program Structure Interface) elements in IntelliJ-based IDEs for various programming languages. The roadmap is divided into short-term, mid-term, and +long-term goals. #### Short-Term Goals (1-3 Months) 1. **Refactoring and Code Cleanup:** - - Simplify complex methods in the `PsiClassContext` class. - - Increase code readability and maintainability by breaking down large methods into smaller, more manageable functions. + +- Simplify complex methods in the `PsiClassContext` class. +- Increase code readability and maintainability by breaking down large methods into smaller, more manageable functions. 2. **Performance Optimization:** - - Profile the current implementation to identify and optimize performance bottlenecks, especially in the `init` method where PSI tree traversal occurs. + +- Profile the current implementation to identify and optimize performance bottlenecks, especially in the `init` method where PSI tree traversal occurs. 3. **Unit Testing:** - - Develop a comprehensive suite of unit tests to cover various scenarios of PSI tree parsing and context generation. - - Ensure that edge cases, such as deeply nested structures and various language-specific constructs, are adequately tested. + +- Develop a comprehensive suite of unit tests to cover various scenarios of PSI tree parsing and context generation. +- Ensure that edge cases, such as deeply nested structures and various language-specific constructs, are adequately tested. 4. **Documentation Enhancement:** - - Improve inline documentation and code comments to better describe the logic and purpose of each method and class property. - - Create a developer guide that explains how to use the `PsiClassContext` class and extend its functionalities. +- Improve inline documentation and code comments to better describe the logic and purpose of each method and class property. +- Create a developer guide that explains how to use the `PsiClassContext` class and extend its functionalities. #### Mid-Term Goals (4-6 Months) 1. **Language Support Expansion:** - - Extend support to additional programming languages beyond Java, Kotlin, and Scala. Prioritize languages commonly used in IntelliJ-based IDEs, such as Python and JavaScript. - - Implement language-specific parsing strategies to handle unique syntax and constructs effectively. + +- Extend support to additional programming languages beyond Java, Kotlin, and Scala. Prioritize languages commonly used in IntelliJ-based IDEs, such as Python + and JavaScript. +- Implement language-specific parsing strategies to handle unique syntax and constructs effectively. 2. **Integration with Other IntelliJ APIs:** - - Explore integration possibilities with other IntelliJ Platform APIs to enhance functionality, such as code formatting, refactoring, and inspections. + +- Explore integration possibilities with other IntelliJ Platform APIs to enhance functionality, such as code formatting, refactoring, and inspections. 3. **User Interface for Context Visualization:** - - Develop a plugin UI component that allows users to visualize and interact with the `PsiClassContext` structure generated from their code. - - Enable features like context navigation, editing, and live updates as the source code changes. +- Develop a plugin UI component that allows users to visualize and interact with the `PsiClassContext` structure generated from their code. +- Enable features like context navigation, editing, and live updates as the source code changes. #### Long-Term Goals (7-12 Months) 1. **Advanced Code Analysis Features:** - - Implement advanced code analysis features that leverage the `PsiClassContext`, such as code complexity analysis, pattern detection, and code smell identification. + +- Implement advanced code analysis features that leverage the `PsiClassContext`, such as code complexity analysis, pattern detection, and code smell + identification. 2. **Machine Learning Integration:** - - Explore the use of machine learning algorithms to predict code patterns and suggest improvements based on the `PsiClassContext`. - - Investigate the feasibility of auto-generating code snippets or entire classes based on the existing project context and user input. + +- Explore the use of machine learning algorithms to predict code patterns and suggest improvements based on the `PsiClassContext`. +- Investigate the feasibility of auto-generating code snippets or entire classes based on the existing project context and user input. 3. **Community and Ecosystem Development:** - - Encourage community contributions by making the project open source (if not already) and establishing a clear contribution guideline. - - Develop a plugin ecosystem that allows third-party developers to extend and build upon the `PsiClassContext` functionalities. + +- Encourage community contributions by making the project open source (if not already) and establishing a clear contribution guideline. +- Develop a plugin ecosystem that allows third-party developers to extend and build upon the `PsiClassContext` functionalities. 4. **Cross-IDE Support:** - - Investigate the possibility of porting the `PsiClassContext` functionalities to other IDEs or code editors, potentially through the Language Server Protocol (LSP) or similar mechanisms. -This roadmap provides a structured approach to evolving the `PsiClassContext` class and its related features. By focusing on immediate improvements and laying the groundwork for future innovations, the project can continuously adapt to meet the needs of its users and leverage new technologies. +- Investigate the possibility of porting the `PsiClassContext` functionalities to other IDEs or code editors, potentially through the Language Server + Protocol (LSP) or similar mechanisms. -# kotlin\com\github\simiacryptus\aicoder\util\psi\PsiTranslationTree.kt +This roadmap provides a structured approach to evolving the `PsiClassContext` class and its related features. By focusing on immediate improvements and laying +the groundwork for future innovations, the project can continuously adapt to meet the needs of its users and leverage new technologies. -Developing a feature for a software project involves a series of steps from initial conception to final release and maintenance. Below is a detailed roadmap for developing a feature, using the `PsiTranslationTree` class from the provided code as an example. This roadmap can be adapted to fit the development of various features in different projects. +# kotlin\com\github\simiacryptus\aicoder\util\psi\PsiTranslationTree.kt +Developing a feature for a software project involves a series of steps from initial conception to final release and maintenance. Below is a detailed roadmap for +developing a feature, using the `PsiTranslationTree` class from the provided code as an example. This roadmap can be adapted to fit the development of various +features in different projects. #### Phase 1: Ideation and Planning -1. **Feature Identification**: Identify the need for a new feature or an enhancement to an existing feature. For `PsiTranslationTree`, the need was to facilitate code translation between different programming languages within the IDE. + +1. **Feature Identification**: Identify the need for a new feature or an enhancement to an existing feature. For `PsiTranslationTree`, the need was to + facilitate code translation between different programming languages within the IDE. 2. **Feasibility Study**: Assess the technical feasibility, potential impact, and resource requirements for the feature. -3. **Requirements Gathering**: Define detailed functional and non-functional requirements. For `PsiTranslationTree`, this includes supported languages, translation accuracy, and performance expectations. +3. **Requirements Gathering**: Define detailed functional and non-functional requirements. For `PsiTranslationTree`, this includes supported languages, + translation accuracy, and performance expectations. 4. **Design and Architecture**: Create high-level design documents outlining the architecture, data flow, and interaction with other components. - #### Phase 2: Development + 1. **Setup Development Environment**: Ensure all necessary tools, libraries, and dependencies are in place. -2. **Implementation**: Start coding the feature based on the design documents. For `PsiTranslationTree`, this involves implementing methods for parsing PSI elements, translating text, and integrating with external translation services. +2. **Implementation**: Start coding the feature based on the design documents. For `PsiTranslationTree`, this involves implementing methods for parsing PSI + elements, translating text, and integrating with external translation services. 3. **Code Review**: Conduct regular code reviews to ensure code quality, adherence to coding standards, and alignment with the design. -4. **Unit Testing**: Write and execute unit tests to cover various scenarios and edge cases. For `PsiTranslationTree`, tests could include translation accuracy, handling of unsupported languages, and performance under different load conditions. - +4. **Unit Testing**: Write and execute unit tests to cover various scenarios and edge cases. For `PsiTranslationTree`, tests could include translation accuracy, + handling of unsupported languages, and performance under different load conditions. #### Phase 3: Testing and Quality Assurance + 1. **Integration Testing**: Test the feature in conjunction with other system components to ensure proper integration. 2. **Performance Testing**: Evaluate the feature's performance, identifying any bottlenecks or scalability issues. 3. **User Acceptance Testing (UAT)**: Allow end-users to test the feature and provide feedback on its functionality and usability. 4. **Bug Fixing**: Address any issues or bugs identified during testing phases. - #### Phase 4: Deployment and Release + 1. **Deployment Planning**: Plan the deployment process, including scheduling and resource allocation. 2. **Release Preparation**: Prepare release notes, documentation, and any necessary migration scripts. 3. **Deployment**: Deploy the feature to the production environment following the deployment plan. 4. **Post-Deployment Testing**: Conduct smoke tests to ensure the feature is working as expected in the production environment. - #### Phase 5: Maintenance and Iteration + 1. **Monitoring**: Continuously monitor the feature for any issues or performance degradation. 2. **User Feedback**: Collect and analyze user feedback for potential improvements or enhancements. 3. **Iterative Development**: Based on feedback and monitoring insights, iterate on the feature to add enhancements or fix issues. 4. **Documentation Updates**: Keep the documentation updated with any changes or new functionalities added to the feature. - #### Phase 6: Retirement + 1. **Assessment**: Regularly assess the feature's relevance, usage, and value to determine if it should be retired. 2. **Deprecation Plan**: If retirement is decided, develop a plan for deprecating the feature, including user notifications and migration paths. 3. **Implementation**: Execute the deprecation plan, ensuring minimal impact on users. -This roadmap provides a comprehensive approach to feature development, from initial idea to retirement, ensuring thorough planning, development, testing, and maintenance for successful feature implementation. +This roadmap provides a comprehensive approach to feature development, from initial idea to retirement, ensuring thorough planning, development, testing, and +maintenance for successful feature implementation. # kotlin\com\github\simiacryptus\aicoder\util\psi\PsiUtil.kt -The code provided is a Kotlin utility class named `PsiUtil` designed for working with PSI (Program Structure Interface) elements in IntelliJ Platform-based IDEs. It provides methods for navigating and manipulating the PSI tree, such as finding elements of specific types, extracting code blocks, and handling text selections. To further develop this utility and enhance its capabilities, a feature development roadmap is proposed below. - +The code provided is a Kotlin utility class named `PsiUtil` designed for working with PSI (Program Structure Interface) elements in IntelliJ Platform-based +IDEs. It provides methods for navigating and manipulating the PSI tree, such as finding elements of specific types, extracting code blocks, and handling text +selections. To further develop this utility and enhance its capabilities, a feature development roadmap is proposed below. #### Phase 1: Core Functionality Enhancements -- **Improved Type Matching**: Enhance the `matchesType` method to support more complex type matching scenarios, including inheritance and interface implementation checks. -- **Bulk Operations**: Implement methods for performing bulk operations on PSI elements, such as renaming all variables of a certain type within a scope or adding annotations to multiple methods simultaneously. -- **Documentation Generation**: Develop a feature to automatically generate documentation comments for methods, classes, and fields based on their types, parameters, and other attributes. +- **Improved Type Matching**: Enhance the `matchesType` method to support more complex type matching scenarios, including inheritance and interface + implementation checks. +- **Bulk Operations**: Implement methods for performing bulk operations on PSI elements, such as renaming all variables of a certain type within a scope or + adding annotations to multiple methods simultaneously. +- **Documentation Generation**: Develop a feature to automatically generate documentation comments for methods, classes, and fields based on their types, + parameters, and other attributes. #### Phase 2: Integration and Usability Improvements -- **IDE Integration**: Create plugins or extensions for popular IDEs (beyond IntelliJ) to make `PsiUtil` functionalities accessible directly from the IDE's interface. -- **User-Friendly API**: Refactor the API to be more intuitive and easier to use for developers who may not be familiar with PSI concepts. This could include higher-level abstractions and simplified method signatures. -- **Performance Optimization**: Profile the utility's performance and optimize slow operations, especially those that can be invoked frequently, such as type matching and tree traversal. +- **IDE Integration**: Create plugins or extensions for popular IDEs (beyond IntelliJ) to make `PsiUtil` functionalities accessible directly from the IDE's + interface. +- **User-Friendly API**: Refactor the API to be more intuitive and easier to use for developers who may not be familiar with PSI concepts. This could include + higher-level abstractions and simplified method signatures. +- **Performance Optimization**: Profile the utility's performance and optimize slow operations, especially those that can be invoked frequently, such as type + matching and tree traversal. #### Phase 3: Advanced Features and Customization -- **Custom PSI Queries**: Implement a query language or a builder pattern for constructing complex PSI queries, allowing users to find elements by combining multiple criteria. -- **Refactoring Support**: Add support for more sophisticated refactoring operations, such as extracting methods, inlining variables, and converting anonymous classes to inner classes. -- **User-Defined Snippets**: Allow users to define and insert code snippets based on templates, which can be populated with context-specific information from the PSI tree. +- **Custom PSI Queries**: Implement a query language or a builder pattern for constructing complex PSI queries, allowing users to find elements by combining + multiple criteria. +- **Refactoring Support**: Add support for more sophisticated refactoring operations, such as extracting methods, inlining variables, and converting anonymous + classes to inner classes. +- **User-Defined Snippets**: Allow users to define and insert code snippets based on templates, which can be populated with context-specific information from + the PSI tree. #### Phase 4: Collaboration and Community Features -- **Shared Snippets Repository**: Create a shared online repository where users can publish their custom snippets, search for snippets created by others, and integrate them into their projects. -- **Collaborative Editing**: Explore the possibility of integrating collaborative editing features, enabling multiple developers to work on the same PSI tree in real-time, potentially useful for remote pair programming. -- **Feedback and Contribution System**: Establish a system for users to provide feedback, report bugs, and contribute code to the `PsiUtil` project, fostering a community of active users and contributors. +- **Shared Snippets Repository**: Create a shared online repository where users can publish their custom snippets, search for snippets created by others, and + integrate them into their projects. +- **Collaborative Editing**: Explore the possibility of integrating collaborative editing features, enabling multiple developers to work on the same PSI tree in + real-time, potentially useful for remote pair programming. +- **Feedback and Contribution System**: Establish a system for users to provide feedback, report bugs, and contribute code to the `PsiUtil` project, fostering a + community of active users and contributors. #### Phase 5: Future Directions -- **Machine Learning Integration**: Investigate the integration of machine learning models to predict and suggest code modifications or refactorings based on the current codebase and past changes. -- **Cross-Language Support**: Extend `PsiUtil` to support PSI trees of languages other than those natively supported by IntelliJ, potentially leveraging language servers or other parsing technologies. -- **Visual PSI Explorer**: Develop a visual tool for exploring and manipulating the PSI tree, providing a more intuitive interface for understanding and modifying the structure of code. -This roadmap outlines a path for the development of `PsiUtil` from its current state to becoming a more powerful, user-friendly, and widely adopted tool for working with PSI in various IDEs and programming languages. +- **Machine Learning Integration**: Investigate the integration of machine learning models to predict and suggest code modifications or refactorings based on + the current codebase and past changes. +- **Cross-Language Support**: Extend `PsiUtil` to support PSI trees of languages other than those natively supported by IntelliJ, potentially leveraging + language servers or other parsing technologies. +- **Visual PSI Explorer**: Develop a visual tool for exploring and manipulating the PSI tree, providing a more intuitive interface for understanding and + modifying the structure of code. -# kotlin\com\github\simiacryptus\aicoder\util\psi\PsiVisitorBase.kt +This roadmap outlines a path for the development of `PsiUtil` from its current state to becoming a more powerful, user-friendly, and widely adopted tool for +working with PSI in various IDEs and programming languages. -The `PsiVisitorBase` class serves as a foundational component for traversing and processing the elements within a PSI (Program Structure Interface) tree in IntelliJ-based IDEs. This class can be extended to create tools and features that analyze, modify, or enhance code within these IDEs. Below is a feature development roadmap that leverages the capabilities of `PsiVisitorBase` to create a suite of powerful development tools. +# kotlin\com\github\simiacryptus\aicoder\util\psi\PsiVisitorBase.kt +The `PsiVisitorBase` class serves as a foundational component for traversing and processing the elements within a PSI (Program Structure Interface) tree in +IntelliJ-based IDEs. This class can be extended to create tools and features that analyze, modify, or enhance code within these IDEs. Below is a feature +development roadmap that leverages the capabilities of `PsiVisitorBase` to create a suite of powerful development tools. #### Phase 1: Basic Analysis Tools -- **Syntax Highlighter**: Develop a feature that extends `PsiVisitorBase` to analyze syntax and apply custom highlighting rules. -- **Code Complexity Analyzer**: Implement a tool that traverses the PSI tree to calculate and display the complexity of methods and classes, helping developers identify areas that may require refactoring. +- **Syntax Highlighter**: Develop a feature that extends `PsiVisitorBase` to analyze syntax and apply custom highlighting rules. +- **Code Complexity Analyzer**: Implement a tool that traverses the PSI tree to calculate and display the complexity of methods and classes, helping developers + identify areas that may require refactoring. #### Phase 2: Code Quality Improvement -- **Unused Code Detector**: Create a feature that identifies and marks unused variables, methods, and classes within a project. -- **Code Smell Detector**: Develop a detector for common code smells, such as long methods, large classes, and inappropriate intimacy between classes, by analyzing the structure and relationships in the PSI tree. +- **Unused Code Detector**: Create a feature that identifies and marks unused variables, methods, and classes within a project. +- **Code Smell Detector**: Develop a detector for common code smells, such as long methods, large classes, and inappropriate intimacy between classes, by + analyzing the structure and relationships in the PSI tree. #### Phase 3: Refactoring Helpers -- **Automatic Refactor Suggestion**: Implement a system that suggests potential refactorings, such as method extraction or class splitting, based on the analysis of code complexity and code smells. -- **Safe Rename Refactoring**: Develop a feature that extends the renaming functionality to ensure that all references are correctly updated across different languages and frameworks used in the project. +- **Automatic Refactor Suggestion**: Implement a system that suggests potential refactorings, such as method extraction or class splitting, based on the + analysis of code complexity and code smells. +- **Safe Rename Refactoring**: Develop a feature that extends the renaming functionality to ensure that all references are correctly updated across different + languages and frameworks used in the project. #### Phase 4: Advanced Code Manipulation -- **Code Generation**: Create a tool that can generate boilerplate code, such as getters/setters, equals/hashCode, and toString methods, by analyzing the fields and methods of a class. -- **Smart Code Templates**: Implement a feature that suggests and inserts code templates based on the current context in the PSI tree, speeding up the development process. +- **Code Generation**: Create a tool that can generate boilerplate code, such as getters/setters, equals/hashCode, and toString methods, by analyzing the fields + and methods of a class. +- **Smart Code Templates**: Implement a feature that suggests and inserts code templates based on the current context in the PSI tree, speeding up the + development process. #### Phase 5: Integration with Other Tools -- **Static Analysis Tool Integration**: Integrate with existing static analysis tools to display warnings and suggestions directly in the IDE, based on the PSI tree analysis. -- **Version Control System Integration**: Develop features that leverage the PSI tree for more intelligent diffing and merging, helping to resolve conflicts more effectively. +- **Static Analysis Tool Integration**: Integrate with existing static analysis tools to display warnings and suggestions directly in the IDE, based on the PSI + tree analysis. +- **Version Control System Integration**: Develop features that leverage the PSI tree for more intelligent diffing and merging, helping to resolve conflicts + more effectively. #### Phase 6: Customization and Extensions + - **Plugin API**: Expose an API that allows other developers to create plugins that extend the functionality of the tools developed from `PsiVisitorBase`. - **User-Defined Rules and Actions**: Allow users to define their own rules for code analysis and actions for refactoring, making the tools highly customizable. - #### Phase 7: Performance Optimization and Scalability + - **Asynchronous Analysis**: Optimize the performance of analysis tools by implementing asynchronous processing of the PSI tree. - **Large Project Support**: Ensure that the tools can scale to work efficiently with large projects, optimizing memory usage and processing time. -This roadmap outlines a comprehensive approach to developing a suite of development tools that leverage the `PsiVisitorBase` class. Each phase builds upon the previous one, gradually increasing the sophistication and utility of the tools. +This roadmap outlines a comprehensive approach to developing a suite of development tools that leverage the `PsiVisitorBase` class. Each phase builds upon the +previous one, gradually increasing the sophistication and utility of the tools. # kotlin\com\github\simiacryptus\aicoder\util\SimpleDiffUtil.kt -To create a feature development roadmap for the `SimpleDiffUtil` class, we'll outline a series of enhancements and new features that could be added to improve its functionality, performance, and usability. This roadmap will be divided into short-term, medium-term, and long-term goals, providing a clear path for development. - +To create a feature development roadmap for the `SimpleDiffUtil` class, we'll outline a series of enhancements and new features that could be added to improve +its functionality, performance, and usability. This roadmap will be divided into short-term, medium-term, and long-term goals, providing a clear path for +development. #### Short-Term Goals (1-3 Months) -1. **Unit Testing and Coverage Improvement**: Develop a comprehensive suite of unit tests to cover all existing functionalities, ensuring that each method behaves as expected under various scenarios. Aim for a high code coverage percentage to guarantee reliability. - -2. **Performance Optimization**: Profile the current implementation to identify any bottlenecks or inefficient operations, especially in the `lookAheadFor` and `lineMatches` methods. Implement optimizations where possible to improve the overall performance of the utility. +1. **Unit Testing and Coverage Improvement**: Develop a comprehensive suite of unit tests to cover all existing functionalities, ensuring that each method + behaves as expected under various scenarios. Aim for a high code coverage percentage to guarantee reliability. -3. **Error Handling and Logging**: Enhance error handling and logging mechanisms to provide more informative feedback for debugging purposes. This includes better handling of edge cases and unexpected inputs. +2. **Performance Optimization**: Profile the current implementation to identify any bottlenecks or inefficient operations, especially in the `lookAheadFor` and + `lineMatches` methods. Implement optimizations where possible to improve the overall performance of the utility. -4. **Documentation and Examples**: Create detailed documentation for each method, including usage examples. This will make the utility more accessible to new users and facilitate easier integration into projects. +3. **Error Handling and Logging**: Enhance error handling and logging mechanisms to provide more informative feedback for debugging purposes. This includes + better handling of edge cases and unexpected inputs. +4. **Documentation and Examples**: Create detailed documentation for each method, including usage examples. This will make the utility more accessible to new + users and facilitate easier integration into projects. #### Medium-Term Goals (4-6 Months) -1. **Interactive Patch Application**: Develop a feature that allows users to interactively apply patches, choosing which changes to include or exclude before finalizing the patched string. This could be implemented as a CLI tool or a simple GUI application. +1. **Interactive Patch Application**: Develop a feature that allows users to interactively apply patches, choosing which changes to include or exclude before + finalizing the patched string. This could be implemented as a CLI tool or a simple GUI application. -2. **Patch Generation**: Extend the utility to not only apply patches but also generate them by comparing two versions of a text. This would make the utility more versatile and useful for a wider range of applications. +2. **Patch Generation**: Extend the utility to not only apply patches but also generate them by comparing two versions of a text. This would make the utility + more versatile and useful for a wider range of applications. -3. **Support for More Diff Formats**: While the current implementation focuses on a simple diff format, adding support for more complex and widely used diff formats (e.g., Unified Diff) would increase the utility's applicability. - -4. **Parallel Processing**: Investigate the feasibility of applying patches in parallel, especially for large texts, to improve performance. This might involve breaking the text into segments that can be processed independently. +3. **Support for More Diff Formats**: While the current implementation focuses on a simple diff format, adding support for more complex and widely used diff + formats (e.g., Unified Diff) would increase the utility's applicability. +4. **Parallel Processing**: Investigate the feasibility of applying patches in parallel, especially for large texts, to improve performance. This might involve + breaking the text into segments that can be processed independently. #### Long-Term Goals (7-12 Months) -1. **Plugin System for Custom Rules**: Implement a plugin system that allows users to define custom rules for handling specific types of changes. This could include custom line matching algorithms, special handling for certain file types, or other user-defined behaviors. +1. **Plugin System for Custom Rules**: Implement a plugin system that allows users to define custom rules for handling specific types of changes. This could + include custom line matching algorithms, special handling for certain file types, or other user-defined behaviors. -2. **Integration with Version Control Systems**: Develop integrations with popular version control systems (e.g., Git, SVN) to allow direct application of patches from commits or pull requests. This would streamline the process of applying changes for developers. +2. **Integration with Version Control Systems**: Develop integrations with popular version control systems (e.g., Git, SVN) to allow direct application of + patches from commits or pull requests. This would streamline the process of applying changes for developers. -3. **Machine Learning for Patch Application**: Explore the use of machine learning algorithms to improve the accuracy of patch application, especially in cases where the context has changed significantly. This could involve training models to better understand the semantics of the text being patched. +3. **Machine Learning for Patch Application**: Explore the use of machine learning algorithms to improve the accuracy of patch application, especially in cases + where the context has changed significantly. This could involve training models to better understand the semantics of the text being patched. -4. **Cloud-Based Service**: Develop a cloud-based version of the utility that offers an API for patch application and generation. This would enable integration with web applications and services, expanding the utility's reach. +4. **Cloud-Based Service**: Develop a cloud-based version of the utility that offers an API for patch application and generation. This would enable integration + with web applications and services, expanding the utility's reach. -By following this roadmap, the `SimpleDiffUtil` class can evolve into a more powerful and versatile tool for handling text differences and patches, catering to a broader audience and a wider range of use cases. +By following this roadmap, the `SimpleDiffUtil` class can evolve into a more powerful and versatile tool for handling text differences and patches, catering to +a broader audience and a wider range of use cases. # kotlin\com\github\simiacryptus\aicoder\util\TextBlockFactory.kt -Developing a feature roadmap for the `TextBlockFactory` interface and its implementation involves planning out the enhancements, new features, and improvements that could be made to make it more robust, flexible, and useful for various applications. Here's a proposed development roadmap: - +Developing a feature roadmap for the `TextBlockFactory` interface and its implementation involves planning out the enhancements, new features, and improvements +that could be made to make it more robust, flexible, and useful for various applications. Here's a proposed development roadmap: #### Phase 1: Core Functionality Enhancement -- **Generic Type Safety Improvement**: Ensure that the generic type `T` extends `TextBlock` in a way that null safety is improved, possibly by removing the nullable type constraint if applicable. + +- **Generic Type Safety Improvement**: Ensure that the generic type `T` extends `TextBlock` in a way that null safety is improved, possibly by removing the + nullable type constraint if applicable. - **Error Handling**: Implement comprehensive error handling within `fromString` to manage null inputs and other potential parsing errors gracefully. - **Performance Optimization**: Profile and optimize the `fromString` and `toString` methods for better performance with large text blocks. - #### Phase 2: Feature Expansion -- **Serialization/Deserialization**: Introduce JSON and XML serialization/deserialization capabilities for `TextBlock` objects to enhance interoperability with other systems and data formats. -- **Asynchronous Support**: Add asynchronous versions of the `fromString` and `toString` methods to support non-blocking operations, especially useful for IO-bound tasks or large text processing. -- **TextBlock Manipulation Utilities**: Develop utility methods for common text block manipulations, such as splitting, merging, and trimming, directly within the interface or through helper classes. +- **Serialization/Deserialization**: Introduce JSON and XML serialization/deserialization capabilities for `TextBlock` objects to enhance interoperability with + other systems and data formats. +- **Asynchronous Support**: Add asynchronous versions of the `fromString` and `toString` methods to support non-blocking operations, especially useful for + IO-bound tasks or large text processing. +- **TextBlock Manipulation Utilities**: Develop utility methods for common text block manipulations, such as splitting, merging, and trimming, directly within + the interface or through helper classes. #### Phase 3: Integration and Compatibility -- **Framework Integration**: Create adapters or integrations for popular Java frameworks (e.g., Spring, Quarkus) to easily use `TextBlockFactory` within those ecosystems. -- **Cross-Language Support**: Explore the feasibility of making `TextBlockFactory` usable from other JVM languages such as Kotlin, Scala, and Groovy, ensuring idiomatic usage and compatibility. -- **Plugin Architecture**: Design a plugin architecture that allows for the easy addition of new `TextBlock` types and formats without modifying the core library, enhancing extensibility. +- **Framework Integration**: Create adapters or integrations for popular Java frameworks (e.g., Spring, Quarkus) to easily use `TextBlockFactory` within those + ecosystems. +- **Cross-Language Support**: Explore the feasibility of making `TextBlockFactory` usable from other JVM languages such as Kotlin, Scala, and Groovy, ensuring + idiomatic usage and compatibility. +- **Plugin Architecture**: Design a plugin architecture that allows for the easy addition of new `TextBlock` types and formats without modifying the core + library, enhancing extensibility. #### Phase 4: Advanced Features -- **Machine Learning Integration**: Investigate integrating machine learning models to enhance the `looksLike` method, allowing for more sophisticated and context-aware text block identification. -- **Text Analysis Tools**: Incorporate text analysis tools directly or through plugins, providing capabilities such as sentiment analysis, keyword extraction, and readability scores for `TextBlock` instances. -- **Customizable Text Processing Pipeline**: Allow users to define custom text processing pipelines (e.g., pre-processing, normalization) that can be applied within the `fromString` method, making the factory more versatile. +- **Machine Learning Integration**: Investigate integrating machine learning models to enhance the `looksLike` method, allowing for more sophisticated and + context-aware text block identification. +- **Text Analysis Tools**: Incorporate text analysis tools directly or through plugins, providing capabilities such as sentiment analysis, keyword extraction, + and readability scores for `TextBlock` instances. +- **Customizable Text Processing Pipeline**: Allow users to define custom text processing pipelines (e.g., pre-processing, normalization) that can be applied + within the `fromString` method, making the factory more versatile. #### Phase 5: Documentation and Community Building -- **Comprehensive Documentation**: Develop thorough documentation, including API reference, usage guides, and best practices for implementing and extending the `TextBlockFactory`. -- **Community Engagement**: Establish a community forum or GitHub repository for users to contribute ideas, report issues, and share custom implementations or plugins. -- **Tutorials and Examples**: Create a series of tutorials and example projects demonstrating various use cases and integrations of the `TextBlockFactory` in real-world applications. +- **Comprehensive Documentation**: Develop thorough documentation, including API reference, usage guides, and best practices for implementing and extending the + `TextBlockFactory`. +- **Community Engagement**: Establish a community forum or GitHub repository for users to contribute ideas, report issues, and share custom implementations or + plugins. +- **Tutorials and Examples**: Create a series of tutorials and example projects demonstrating various use cases and integrations of the `TextBlockFactory` in + real-world applications. #### Phase 6: Continuous Improvement -- **Feedback Loop**: Implement a structured feedback loop with users and contributors to continually assess the utility and usability of the `TextBlockFactory`, identifying areas for improvement. -- **Regular Updates**: Commit to a regular schedule of updates, including bug fixes, performance enhancements, and feature additions based on community feedback and technological advancements. -This roadmap provides a structured approach to evolving the `TextBlockFactory` interface and its ecosystem, focusing on making it more powerful, user-friendly, and adaptable to a wide range of applications. +- **Feedback Loop**: Implement a structured feedback loop with users and contributors to continually assess the utility and usability of the `TextBlockFactory`, + identifying areas for improvement. +- **Regular Updates**: Commit to a regular schedule of updates, including bug fixes, performance enhancements, and feature additions based on community feedback + and technological advancements. -# kotlin\com\github\simiacryptus\aicoder\util\UITools.kt +This roadmap provides a structured approach to evolving the `TextBlockFactory` interface and its ecosystem, focusing on making it more powerful, user-friendly, +and adaptable to a wide range of applications. +# kotlin\com\github\simiacryptus\aicoder\util\UITools.kt #### Feature Development Roadmap for UITools Library - ##### Phase 1: Core Functionality Enhancements + - **1.1 Document Manipulation Improvements** - Add support for more complex text manipulations, such as multi-caret editing and batch operations for efficiency. - Implement undo/redo functionality that is more granular and reliable. @@ -2610,8 +3284,8 @@ This roadmap provides a structured approach to evolving the `TextBlockFactory` i - Optimize the thread pool and executor services for better performance and resource management. - Implement a mechanism to dynamically adjust thread pool sizes based on workload and system resources. - ##### Phase 2: User Experience and Usability + - **2.1 Dialog and Form Builders** - Develop a more intuitive and flexible API for constructing dialogs and forms, reducing boilerplate code. - Introduce layout managers and templates for common dialog patterns to streamline development. @@ -2624,8 +3298,8 @@ This roadmap provides a structured approach to evolving the `TextBlockFactory` i - Audit and improve accessibility features across the UI toolkit, ensuring compliance with accessibility standards. - Add support for screen readers and keyboard navigation enhancements. - ##### Phase 3: Integration and Extensibility + - **3.1 Plugin Architecture** - Develop a plugin system that allows third-party extensions to add new UI components, dialogs, and utilities. - Create a marketplace or repository for sharing and discovering plugins. @@ -2638,8 +3312,8 @@ This roadmap provides a structured approach to evolving the `TextBlockFactory` i - Implement advanced code generation features that can scaffold entire UIs or components based on templates and specifications. - Introduce a template language and editor for creating and customizing code templates. - ##### Phase 4: Performance and Scalability + - **4.1 Performance Optimization** - Conduct a comprehensive performance audit and optimize hot paths and memory usage. - Implement lazy loading and asynchronous operations for UI components to improve responsiveness. @@ -2652,8 +3326,8 @@ This roadmap provides a structured approach to evolving the `TextBlockFactory` i - Develop a suite of automated tests covering UI components, functionality, and integration points. - Introduce performance benchmarks and regression tests to prevent performance degradation over time. - ##### Phase 5: Documentation and Community + - **5.1 Comprehensive Documentation** - Create detailed documentation covering all aspects of the UI toolkit, including tutorials, API references, and best practices. - Provide examples and sample projects demonstrating the use of the toolkit in real-world applications. @@ -2666,95 +3340,108 @@ This roadmap provides a structured approach to evolving the `TextBlockFactory` i - Encourage open-source contributions by streamlining the contribution process and recognizing contributors. - Collaborate with academic institutions and industry partners to drive research and development in UI technologies. -This roadmap outlines a strategic plan for the development of the UITools library, focusing on enhancing core functionalities, improving user experience, extending integration capabilities, optimizing performance, and fostering a vibrant community. Each phase builds upon the previous ones, ensuring a solid foundation for future innovations. +This roadmap outlines a strategic plan for the development of the UITools library, focusing on enhancing core functionalities, improving user experience, +extending integration capabilities, optimizing performance, and fostering a vibrant community. Each phase builds upon the previous ones, ensuring a solid +foundation for future innovations. # resources\META-INF\plugin.xml -Creating a feature development roadmap for the AI Coding Assistant plugin involves outlining the planned enhancements, new features, and improvements over time. This roadmap will help guide development efforts, prioritize tasks, and communicate the project's direction to stakeholders. Here's a proposed roadmap segmented into phases: - +Creating a feature development roadmap for the AI Coding Assistant plugin involves outlining the planned enhancements, new features, and improvements over time. +This roadmap will help guide development efforts, prioritize tasks, and communicate the project's direction to stakeholders. Here's a proposed roadmap segmented +into phases: #### Phase 1: Core Functionality Enhancement + - **Q2 2023** - **Dictation Feature Improvement**: Enhance the dictation feature to support more languages and dialects, leveraging advancements in OpenAI's Whisper API. - **Replace Options Enhancement**: Improve the context understanding and suggestion accuracy for the Replace Options feature. - **Temperature Control Widget**: Introduce a more intuitive UI for adjusting the AI's creativity level directly from the status bar. - #### Phase 2: User Experience and Accessibility + - **Q3 2023** - - **UI/UX Overhaul**: Redesign the plugin's UI to make it more user-friendly and accessible, including support for high-contrast themes for visually impaired developers. + - **UI/UX Overhaul**: Redesign the plugin's UI to make it more user-friendly and accessible, including support for high-contrast themes for visually impaired + developers. - **Documentation and Tutorials**: Develop comprehensive documentation and video tutorials covering all features of the plugin to assist new users. - **Feedback Mechanism**: Implement a direct feedback mechanism within the plugin for users to report issues or suggest improvements. - #### Phase 3: Advanced AI Features + - **Q4 2023 - Q1 2024** - **Code Chat Integration**: Integrate a ChatGPT-like interface to allow developers to discuss code logic and get suggestions directly within the IDE. - **AI-Powered Refactoring Tools**: Develop AI-powered tools for code refactoring, including smart variable renaming and code structure optimization. - - **Automated Code Review**: Introduce an automated code review feature that can suggest improvements and identify potential issues based on best coding practices. - + - **Automated Code Review**: Introduce an automated code review feature that can suggest improvements and identify potential issues based on best coding + practices. #### Phase 4: Collaboration and Team Features + - **Q2 2024** - **Team Settings Sync**: Allow teams to synchronize plugin settings across members to ensure a consistent development environment. - - **Collaborative Coding via AI**: Enable features that support collaborative coding sessions powered by AI, allowing team members to co-develop code in real-time. - - **Integration with Version Control Systems**: Enhance the plugin to better integrate with version control systems like Git, offering AI-powered commit message suggestions and code merge conflict resolution. - + - **Collaborative Coding via AI**: Enable features that support collaborative coding sessions powered by AI, allowing team members to co-develop code in + real-time. + - **Integration with Version Control Systems**: Enhance the plugin to better integrate with version control systems like Git, offering AI-powered commit + message suggestions and code merge conflict resolution. #### Phase 5: Expansion and Integration + - **Q3 2024 onwards** - - **Language Support Expansion**: Continuously expand the number of programming languages supported by the plugin, based on community feedback and usage trends. + - **Language Support Expansion**: Continuously expand the number of programming languages supported by the plugin, based on community feedback and usage + trends. - **IDE Support Expansion**: Extend the plugin to support additional IDEs beyond IntelliJ, such as VS Code and Eclipse. - - **External Tools Integration**: Integrate with external tools and services, such as Docker, Kubernetes, and cloud service providers, to offer AI-powered assistance for configuration and deployment tasks. - + - **External Tools Integration**: Integrate with external tools and services, such as Docker, Kubernetes, and cloud service providers, to offer AI-powered + assistance for configuration and deployment tasks. #### Continuous Improvement + - **Ongoing** - **Performance Optimization**: Continuously monitor and improve the plugin's performance to ensure a smooth user experience. - **Security Enhancements**: Regularly update the plugin to address security concerns and protect user data. - - **Community Engagement**: Engage with the developer community through forums, social media, and developer conferences to gather feedback and ideas for new features. + - **Community Engagement**: Engage with the developer community through forums, social media, and developer conferences to gather feedback and ideas for new + features. -This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. Regular updates will be provided to keep users informed of progress and any adjustments to the plan. +This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. Regular updates will be provided to keep users +informed of progress and any adjustments to the plan. # resources\permissions\admin.txt -Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features and improvements you plan to implement along the way. This roadmap serves as a strategic document guiding your development team and stakeholders through the planned evolution of your product. Here's how you can create a feature development roadmap: - +Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features +and improvements you plan to implement along the way. This roadmap serves as a strategic document guiding your development team and stakeholders through the +planned evolution of your product. Here's how you can create a feature development roadmap: #### 1. Define Your Product Vision -Start by clearly defining the long-term vision for your product. What are the ultimate goals you aim to achieve? This vision will serve as the north star for your roadmap, ensuring that all features contribute towards these overarching objectives. - +Start by clearly defining the long-term vision for your product. What are the ultimate goals you aim to achieve? This vision will serve as the north star for +your roadmap, ensuring that all features contribute towards these overarching objectives. #### 2. Gather Input -Collect ideas, feedback, and requests from all relevant stakeholders, including customers, team members, and executives. This will help ensure that your roadmap is comprehensive and aligned with the needs and expectations of those it impacts. - +Collect ideas, feedback, and requests from all relevant stakeholders, including customers, team members, and executives. This will help ensure that your roadmap +is comprehensive and aligned with the needs and expectations of those it impacts. #### 3. Prioritize Features -Not all features are created equal. Prioritize them based on factors such as customer impact, business value, and technical feasibility. Consider using a framework like RICE (Reach, Impact, Confidence, Effort) or MoSCoW (Must have, Should have, Could have, Won't have) for this process. - +Not all features are created equal. Prioritize them based on factors such as customer impact, business value, and technical feasibility. Consider using a +framework like RICE (Reach, Impact, Confidence, Effort) or MoSCoW (Must have, Should have, Could have, Won't have) for this process. #### 4. Set Milestones and Timelines -Break down the development process into manageable milestones, each with its own set of features and improvements. Assign realistic timelines to these milestones, taking into account your team's capacity and any dependencies between tasks. - +Break down the development process into manageable milestones, each with its own set of features and improvements. Assign realistic timelines to these +milestones, taking into account your team's capacity and any dependencies between tasks. #### 5. Choose a Format -Decide on how you will visualize your roadmap. This could be a simple spreadsheet, a Gantt chart, or specialized roadmap software. The format should allow for easy updates and be accessible to all stakeholders. - +Decide on how you will visualize your roadmap. This could be a simple spreadsheet, a Gantt chart, or specialized roadmap software. The format should allow for +easy updates and be accessible to all stakeholders. #### 6. Communicate and Share -Share the roadmap with your team and stakeholders, ensuring everyone understands the direction and priorities. Be open to feedback and prepared to make adjustments as necessary. - +Share the roadmap with your team and stakeholders, ensuring everyone understands the direction and priorities. Be open to feedback and prepared to make +adjustments as necessary. #### 7. Review and Update Regularly -Your roadmap is a living document. Regularly review and update it to reflect any changes in priorities, timelines, or market conditions. This will help keep your development efforts on track and aligned with your product vision. - +Your roadmap is a living document. Regularly review and update it to reflect any changes in priorities, timelines, or market conditions. This will help keep +your development efforts on track and aligned with your product vision. #### Example Code for a Simple Roadmap in a Spreadsheet Format @@ -2781,52 +3468,54 @@ roadmap_df.set_index("Feature", inplace=True) print(roadmap_df) ``` -This Python code snippet creates a simple feature development roadmap using a DataFrame from the pandas library. It lists features along with their priorities, current status, and estimated completion dates. This format can be easily shared as a CSV file or integrated into project management tools. +This Python code snippet creates a simple feature development roadmap using a DataFrame from the pandas library. It lists features along with their priorities, +current status, and estimated completion dates. This format can be easily shared as a CSV file or integrated into project management tools. # resources\permissions\globalkey.txt -Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features and improvements you plan to implement along the way. This roadmap serves as a strategic document guiding the development team, stakeholders, and sometimes even customers, on the journey your product is set to undertake. Here's how you can create a feature development roadmap: - +Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features +and improvements you plan to implement along the way. This roadmap serves as a strategic document guiding the development team, stakeholders, and sometimes even +customers, on the journey your product is set to undertake. Here's how you can create a feature development roadmap: #### 1. Define Your Product Vision -Start by clearly defining the long-term vision of your product. This vision should encapsulate what you aim to achieve in the future and serve as the guiding star for all your development efforts. - +Start by clearly defining the long-term vision of your product. This vision should encapsulate what you aim to achieve in the future and serve as the guiding +star for all your development efforts. #### 2. Gather Input -Collect ideas, feedback, and suggestions from all relevant sources, including customers, stakeholders, the development team, and market research. This will help ensure that your roadmap is comprehensive and aligned with user needs and business goals. - +Collect ideas, feedback, and suggestions from all relevant sources, including customers, stakeholders, the development team, and market research. This will help +ensure that your roadmap is comprehensive and aligned with user needs and business goals. #### 3. Prioritize Features -Not all features are created equal. Prioritize the features based on factors such as customer impact, business value, and technical feasibility. Methods like the MoSCoW method (Must have, Should have, Could have, Won't have) can be helpful in this process. - +Not all features are created equal. Prioritize the features based on factors such as customer impact, business value, and technical feasibility. Methods like +the MoSCoW method (Must have, Should have, Could have, Won't have) can be helpful in this process. #### 4. Set Clear Objectives and Key Results (OKRs) -For each feature or set of features, define clear objectives and measurable key results. This will not only help in tracking progress but also ensure that every feature contributes towards the overall product vision. - +For each feature or set of features, define clear objectives and measurable key results. This will not only help in tracking progress but also ensure that every +feature contributes towards the overall product vision. #### 5. Create a Timeline -Based on the priorities and the resources available, create a realistic timeline for the development and release of each feature. This timeline should be flexible enough to accommodate changes and unforeseen challenges. - +Based on the priorities and the resources available, create a realistic timeline for the development and release of each feature. This timeline should be +flexible enough to accommodate changes and unforeseen challenges. #### 6. Visualize the Roadmap -Use a tool or platform that allows you to visualize the roadmap in a clear and accessible manner. This could be a simple spreadsheet, a Gantt chart, or specialized software like Aha!, Trello, or Jira Roadmaps. - +Use a tool or platform that allows you to visualize the roadmap in a clear and accessible manner. This could be a simple spreadsheet, a Gantt chart, or +specialized software like Aha!, Trello, or Jira Roadmaps. #### 7. Communicate and Share -Share the roadmap with all relevant parties, ensuring that everyone involved has a clear understanding of the direction and priorities. Regular updates and revisions will be necessary as projects progress and priorities shift. - +Share the roadmap with all relevant parties, ensuring that everyone involved has a clear understanding of the direction and priorities. Regular updates and +revisions will be necessary as projects progress and priorities shift. #### 8. Review and Adjust -Regularly review the roadmap to assess progress and realign priorities as needed. The development process is dynamic, and your roadmap should be too, adapting to feedback, market changes, and the lessons learned along the way. - +Regularly review the roadmap to assess progress and realign priorities as needed. The development process is dynamic, and your roadmap should be too, adapting +to feedback, market changes, and the lessons learned along the way. #### Example of a Simple Roadmap Entry: @@ -2845,110 +3534,123 @@ Regularly review the roadmap to assess progress and realign priorities as needed - **Status**: In Progress ``` -This example outlines a specific set of goals for a quarter, focusing on enhancing the user experience by improving performance and usability. It includes objectives, key results, the features planned to achieve these results, the teams involved, and the current status. This format can be replicated and adjusted for each set of features or improvements on your roadmap. +This example outlines a specific set of goals for a quarter, focusing on enhancing the user experience by improving performance and usability. It includes +objectives, key results, the features planned to achieve these results, the teams involved, and the current status. This format can be replicated and adjusted +for each set of features or improvements on your roadmap. # resources\META-INF\toolbarIcon.svg -Creating a feature development roadmap involves outlining the key features and enhancements planned for a product over a specific period. This roadmap serves as a strategic document guiding the development team and informing stakeholders about the product's direction. Here's a step-by-step guide to creating a feature development roadmap: - +Creating a feature development roadmap involves outlining the key features and enhancements planned for a product over a specific period. This roadmap serves as +a strategic document guiding the development team and informing stakeholders about the product's direction. Here's a step-by-step guide to creating a feature +development roadmap: #### 1. Define the Product Vision and Strategy + - **Objective:** Establish a clear understanding of what you aim to achieve with the product in the long term. - **Activities:** - Define the product vision. - Align the product strategy with business goals. - Identify the target market and user needs. - #### 2. Gather and Prioritize Requirements + - **Objective:** Collect and prioritize the features and improvements based on user needs, business objectives, and technical feasibility. - **Activities:** - Conduct user research and gather feedback. - Collaborate with stakeholders to identify requirements. - Prioritize features based on value, urgency, and effort. - #### 3. Set Clear Goals and Objectives + - **Objective:** Define specific, measurable, achievable, relevant, and time-bound (SMART) goals for each feature or enhancement. - **Activities:** - Establish key performance indicators (KPIs) for each feature. - Set deadlines and milestones. - Define success criteria for feature implementation. - #### 4. Plan the Roadmap + - **Objective:** Organize the prioritized features into a timeline, considering dependencies, resources, and strategic importance. - **Activities:** - Create a timeline for feature development. - Allocate resources and assign responsibilities. - Identify dependencies and potential bottlenecks. - #### 5. Communicate the Roadmap + - **Objective:** Share the roadmap with all relevant stakeholders to ensure alignment and set expectations. - **Activities:** - Present the roadmap to stakeholders, including the development team, management, and customers. - Gather feedback and make adjustments as necessary. - Ensure transparency and keep the roadmap accessible. - #### 6. Execute and Monitor Progress + - **Objective:** Implement the planned features according to the roadmap while monitoring progress and adapting to changes. - **Activities:** - Kick off development sprints based on the roadmap. - Monitor progress against goals and KPIs. - Conduct regular reviews and adjust the roadmap as needed. - #### 7. Review and Update the Roadmap + - **Objective:** Regularly review the roadmap to reflect changes in priorities, market conditions, and feedback. - **Activities:** - Schedule periodic roadmap reviews. - Update the roadmap based on new information and achievements. - Communicate changes to all stakeholders. - #### Example Roadmap Timeline: + - **Q1:** User research and feedback gathering. - **Q2:** Development of priority features and enhancements. - **Q3:** Beta testing with select users and gathering feedback. - **Q4:** Final adjustments and launch of new features. - **Ongoing:** Monitoring, feedback collection, and iterative improvements. -Creating a feature development roadmap is an iterative process that requires flexibility, clear communication, and a focus on delivering value to users and the business. +Creating a feature development roadmap is an iterative process that requires flexibility, clear communication, and a focus on delivering value to users and the +business. # resources\permissions\execute.txt -Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features and improvements you plan to implement along the way. This roadmap serves as a strategic document guiding your development team and stakeholders through the planned evolution of your product. Here's how you can create a feature development roadmap: - +Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features +and improvements you plan to implement along the way. This roadmap serves as a strategic document guiding your development team and stakeholders through the +planned evolution of your product. Here's how you can create a feature development roadmap: #### 1. Define Your Product Vision and Strategy -Start by clearly defining the long-term vision for your product. What are the main goals you aim to achieve? How does your product stand out from the competition? Your product strategy should align with this vision, detailing how you plan to achieve these goals. +Start by clearly defining the long-term vision for your product. What are the main goals you aim to achieve? How does your product stand out from the +competition? Your product strategy should align with this vision, detailing how you plan to achieve these goals. #### 2. Gather and Prioritize Ideas -Collect feature ideas and improvements from various sources, including customer feedback, competitor analysis, and internal suggestions. Prioritize these ideas based on factors such as customer impact, business value, and feasibility. +Collect feature ideas and improvements from various sources, including customer feedback, competitor analysis, and internal suggestions. Prioritize these ideas +based on factors such as customer impact, business value, and feasibility. #### 3. Set Clear Objectives and Key Results (OKRs) -Define what success looks like for each feature or improvement. Setting Objectives and Key Results (OKRs) helps in measuring progress and ensures that every feature contributes towards the overall product strategy. +Define what success looks like for each feature or improvement. Setting Objectives and Key Results (OKRs) helps in measuring progress and ensures that every +feature contributes towards the overall product strategy. #### 4. Create a Timeline -Organize the prioritized features into a timeline, taking into account dependencies between features, resource availability, and key milestones. This timeline will form the backbone of your roadmap. +Organize the prioritized features into a timeline, taking into account dependencies between features, resource availability, and key milestones. This timeline +will form the backbone of your roadmap. #### 5. Choose the Right Tools -Select a tool or platform to create and share your roadmap. This could be a specialized roadmap software, a project management tool, or even a simple spreadsheet, depending on your needs and budget. +Select a tool or platform to create and share your roadmap. This could be a specialized roadmap software, a project management tool, or even a simple +spreadsheet, depending on your needs and budget. #### 6. Communicate and Share the Roadmap -Share the roadmap with all stakeholders, including the development team, marketing, sales, and, if appropriate, customers. Ensure everyone understands the vision, the priorities, and the timeline. +Share the roadmap with all stakeholders, including the development team, marketing, sales, and, if appropriate, customers. Ensure everyone understands the +vision, the priorities, and the timeline. #### 7. Review and Update Regularly -Your roadmap is a living document. Regularly review and update it to reflect any changes in priorities, market conditions, or resource availability. This ensures your development efforts remain aligned with your product strategy. +Your roadmap is a living document. Regularly review and update it to reflect any changes in priorities, market conditions, or resource availability. This +ensures your development efforts remain aligned with your product strategy. #### Example Code: Creating a Simple Roadmap in a Spreadsheet @@ -2977,97 +3679,118 @@ roadmap_df.sort_values(by=["Priority", "Estimated Launch"], ascending=[False, Tr print(roadmap_df) ``` -This example uses Python with pandas to create a simple feature development roadmap, represented as a DataFrame. It lists features along with their priority, estimated launch quarter, and current status. This can be a starting point for creating a more detailed and interactive roadmap using specialized tools. +This example uses Python with pandas to create a simple feature development roadmap, represented as a DataFrame. It lists features along with their priority, +estimated launch quarter, and current status. This can be a starting point for creating a more detailed and interactive roadmap using specialized tools. # resources\META-INF\pluginIcon.svg -Creating a feature development roadmap involves several steps to ensure that the development process is organized, prioritized, and aligned with the overall goals of the project. Here's a structured approach to creating a feature development roadmap: - +Creating a feature development roadmap involves several steps to ensure that the development process is organized, prioritized, and aligned with the overall +goals of the project. Here's a structured approach to creating a feature development roadmap: #### 1. Define the Vision and Objectives -- **Vision Statement:** Clearly articulate the long-term vision of the product. What problem does it solve? Who is it for? -- **Objectives:** List the key objectives that the product aims to achieve in the short to medium term. These should be specific, measurable, achievable, relevant, and time-bound (SMART). +- **Vision Statement:** Clearly articulate the long-term vision of the product. What problem does it solve? Who is it for? +- **Objectives:** List the key objectives that the product aims to achieve in the short to medium term. These should be specific, measurable, achievable, + relevant, and time-bound (SMART). #### 2. Gather and Prioritize Requirements -- **Requirement Gathering:** Collect feature ideas and requirements from all stakeholders, including customers, product managers, sales, marketing, and support teams. -- **Prioritization:** Use a framework like MoSCoW (Must have, Should have, Could have, Won't have this time) or the Kano Model to prioritize features based on their value to the customer and the business. +- **Requirement Gathering:** Collect feature ideas and requirements from all stakeholders, including customers, product managers, sales, marketing, and support + teams. +- **Prioritization:** Use a framework like MoSCoW (Must have, Should have, Could have, Won't have this time) or the Kano Model to prioritize features based on + their value to the customer and the business. #### 3. Define Key Features and User Stories -- **Key Features:** Break down the objectives into key features that need to be developed. Describe what each feature does and why it's important. -- **User Stories:** For each key feature, write user stories that describe how a user will interact with the feature. This helps in understanding the feature from the user's perspective. +- **Key Features:** Break down the objectives into key features that need to be developed. Describe what each feature does and why it's important. +- **User Stories:** For each key feature, write user stories that describe how a user will interact with the feature. This helps in understanding the feature + from the user's perspective. #### 4. Set Milestones and Timelines + - **Milestones:** Identify major milestones in the development process. This could include completing the design, finishing the MVP, public beta release, etc. - **Timelines:** Assign realistic timelines to each milestone and feature development based on the team's capacity and dependencies. - #### 5. Allocate Resources + - **Team Allocation:** Determine which team members will work on which features based on their skills and experience. - **Budget:** Ensure that the budget is allocated efficiently across the development process, including design, development, testing, and marketing. - #### 6. Risk Assessment and Mitigation -- **Risk Assessment:** Identify potential risks that could impact the roadmap, such as technical challenges, market changes, or resource constraints. -- **Mitigation Plans:** Develop strategies to mitigate these risks, such as having a buffer in the timeline, cross-training team members, or conducting early market research. +- **Risk Assessment:** Identify potential risks that could impact the roadmap, such as technical challenges, market changes, or resource constraints. +- **Mitigation Plans:** Develop strategies to mitigate these risks, such as having a buffer in the timeline, cross-training team members, or conducting early + market research. #### 7. Communication Plan + - **Internal Communication:** Establish regular check-ins and updates within the team and with stakeholders to ensure everyone is aligned and informed. - **External Communication:** Plan how and when to communicate progress and releases to customers and users. - #### 8. Review and Adapt + - **Regular Reviews:** Schedule regular roadmap reviews to assess progress, discuss challenges, and make adjustments as needed. - **Adaptability:** Be prepared to adapt the roadmap based on feedback, new information, or changes in priorities. - #### Example Roadmap Layout + 1. **Q1:** - - Complete user research and finalize product vision. - - Develop MVP with core features. + +- Complete user research and finalize product vision. +- Develop MVP with core features. + 2. **Q2:** - - Launch public beta and collect user feedback. - - Begin development on "Should have" features. + +- Launch public beta and collect user feedback. +- Begin development on "Should have" features. + 3. **Q3:** - - Official public release with additional features. - - Start working on "Could have" features based on user feedback. + +- Official public release with additional features. +- Start working on "Could have" features based on user feedback. + 4. **Q4:** - - Expand marketing efforts and partnerships. - - Evaluate the year's progress and plan for the next year. + +- Expand marketing efforts and partnerships. +- Evaluate the year's progress and plan for the next year. Remember, a feature development roadmap is a living document that should evolve based on the project's progress and external factors. # resources\permissions\read.txt -Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features and improvements you plan to implement along the way. This roadmap serves as a strategic document guiding the development team and stakeholders through the planned evolution of the product. Here's how you can create a feature development roadmap: - +Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features +and improvements you plan to implement along the way. This roadmap serves as a strategic document guiding the development team and stakeholders through the +planned evolution of the product. Here's how you can create a feature development roadmap: #### 1. Define Your Product Vision and Strategy -Start by clearly defining the long-term vision for your product. What are the main goals you aim to achieve? How does your product stand out from the competition? Your product strategy should align with this vision, detailing how you plan to achieve these goals. +Start by clearly defining the long-term vision for your product. What are the main goals you aim to achieve? How does your product stand out from the +competition? Your product strategy should align with this vision, detailing how you plan to achieve these goals. #### 2. Gather and Prioritize Ideas -Collect feature ideas and improvements from various sources, including customer feedback, competitor analysis, and internal suggestions. Prioritize these ideas based on factors such as customer value, strategic alignment, and development effort. +Collect feature ideas and improvements from various sources, including customer feedback, competitor analysis, and internal suggestions. Prioritize these ideas +based on factors such as customer value, strategic alignment, and development effort. #### 3. Set Clear Objectives and Key Results (OKRs) -Define what success looks like for each feature or improvement. Setting Objectives and Key Results (OKRs) helps in measuring progress and ensures that the team is aligned towards achieving common goals. +Define what success looks like for each feature or improvement. Setting Objectives and Key Results (OKRs) helps in measuring progress and ensures that the team +is aligned towards achieving common goals. #### 4. Create a Timeline -Based on the priorities and the resources available, create a timeline for the development and release of each feature. This timeline should be realistic, taking into account the complexities of development and potential dependencies between features. +Based on the priorities and the resources available, create a timeline for the development and release of each feature. This timeline should be realistic, +taking into account the complexities of development and potential dependencies between features. #### 5. Assign Responsibilities -Clearly define who is responsible for each part of the roadmap. This includes not only the development tasks but also responsibilities related to design, testing, marketing, and customer support. +Clearly define who is responsible for each part of the roadmap. This includes not only the development tasks but also responsibilities related to design, +testing, marketing, and customer support. #### 6. Communicate and Update Regularly -Share the roadmap with all stakeholders, including the development team, management, and possibly even customers. Regularly update the roadmap to reflect any changes in priorities, timelines, or objectives based on new information or feedback. +Share the roadmap with all stakeholders, including the development team, management, and possibly even customers. Regularly update the roadmap to reflect any +changes in priorities, timelines, or objectives based on new information or feedback. #### Example of a Simple Feature Development Roadmap Structure: @@ -3115,44 +3838,54 @@ Share the roadmap with all stakeholders, including the development team, managem * Mechanisms for collecting and incorporating feedback into the roadmap. ``` -This structure provides a clear overview of what the team plans to achieve, aligning everyone towards common goals and facilitating better planning and execution. Remember, a feature development roadmap is a living document that should evolve based on new insights and feedback. +This structure provides a clear overview of what the team plans to achieve, aligning everyone towards common goals and facilitating better planning and +execution. Remember, a feature development roadmap is a living document that should evolve based on new insights and feedback. # resources\permissions\write.txt -Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features and improvements you plan to implement along the way. This roadmap serves as a strategic document that aligns the team and stakeholders around the product's vision and priorities. Here's a step-by-step guide to help you create an effective feature development roadmap: - +Creating a feature development roadmap involves outlining the path from the current state of your product to the envisioned future state, with all the features +and improvements you plan to implement along the way. This roadmap serves as a strategic document that aligns the team and stakeholders around the product's +vision and priorities. Here's a step-by-step guide to help you create an effective feature development roadmap: #### 1. Define Your Product Vision and Strategy -Before you start plotting features on a roadmap, clearly define the long-term vision for your product. What problem does it solve? Who is it for? How does it stand out from competitors? Your product strategy should outline how you plan to achieve this vision. +Before you start plotting features on a roadmap, clearly define the long-term vision for your product. What problem does it solve? Who is it for? How does it +stand out from competitors? Your product strategy should outline how you plan to achieve this vision. #### 2. Gather Input -Collect ideas, feedback, and requests from all relevant stakeholders, including customers, sales, marketing, customer support, and the development team. This will ensure your roadmap is comprehensive and aligned with user needs and business goals. +Collect ideas, feedback, and requests from all relevant stakeholders, including customers, sales, marketing, customer support, and the development team. This +will ensure your roadmap is comprehensive and aligned with user needs and business goals. #### 3. Prioritize Features -Not all features are created equal. Use a framework like RICE (Reach, Impact, Confidence, Effort) or MoSCoW (Must have, Should have, Could have, Won't have) to prioritize features based on their value to the customer and the business, as well as the effort required to develop them. +Not all features are created equal. Use a framework like RICE (Reach, Impact, Confidence, Effort) or MoSCoW (Must have, Should have, Could have, Won't have) to +prioritize features based on their value to the customer and the business, as well as the effort required to develop them. #### 4. Define Themes and Epics -Group related features into themes or epics to provide a higher-level view of what you aim to achieve. This helps communicate the roadmap more effectively by focusing on outcomes rather than a list of features. +Group related features into themes or epics to provide a higher-level view of what you aim to achieve. This helps communicate the roadmap more effectively by +focusing on outcomes rather than a list of features. #### 5. Set Milestones and Timelines -Determine key milestones and approximate timelines for your features. Be realistic about development time and consider dependencies between features. It's often helpful to use a time horizon (e.g., now, next, later) rather than specific dates to allow for flexibility. +Determine key milestones and approximate timelines for your features. Be realistic about development time and consider dependencies between features. It's often +helpful to use a time horizon (e.g., now, next, later) rather than specific dates to allow for flexibility. #### 6. Choose the Right Tools -Select a tool or platform to create and share your roadmap. It should allow you to easily update the roadmap and share it with stakeholders. Popular options include product management software like Aha!, Productboard, or Trello. +Select a tool or platform to create and share your roadmap. It should allow you to easily update the roadmap and share it with stakeholders. Popular options +include product management software like Aha!, Productboard, or Trello. #### 7. Communicate and Share -Share the roadmap with all stakeholders and keep them updated on progress. Your roadmap is a living document that will evolve as you gather more feedback and learn from development. +Share the roadmap with all stakeholders and keep them updated on progress. Your roadmap is a living document that will evolve as you gather more feedback and +learn from development. #### 8. Review and Adjust Regularly -Regularly review your roadmap and adjust as needed based on new information, feedback, or changes in business priorities. This ensures your product development remains aligned with your product vision and market needs. +Regularly review your roadmap and adjust as needed based on new information, feedback, or changes in business priorities. This ensures your product development +remains aligned with your product vision and market needs. #### Example of a Simple Roadmap Entry: @@ -3185,663 +3918,827 @@ Regularly review your roadmap and adjust as needed based on new information, fee } ``` -This JSON structure represents a simplified version of a feature development roadmap, focusing on a major theme of "User Experience Enhancement" with specific epics and features listed under it, along with their priorities and current status. This format can be adapted and expanded based on the complexity of your product and development process. +This JSON structure represents a simplified version of a feature development roadmap, focusing on a major theme of "User Experience Enhancement" with specific +epics and features listed under it, along with their priorities and current status. This format can be adapted and expanded based on the complexity of your +product and development process. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\CustomEditAction.kt -The code provided outlines a Kotlin class `CustomEditAction` that extends `SelectionAction` and is designed for an IntelliJ IDEA plugin. This plugin action allows users to edit code snippets by providing instructions to a virtual API, which then returns the edited code. The virtual API is simulated through a `ChatProxy` that interfaces with an AI model. This setup suggests a sophisticated plugin that leverages AI for code modification tasks. Based on this, a feature development roadmap can be structured as follows: - +The code provided outlines a Kotlin class `CustomEditAction` that extends `SelectionAction` and is designed for an IntelliJ IDEA plugin. This plugin +action allows users to edit code snippets by providing instructions to a virtual API, which then returns the edited code. The virtual API is simulated through a +`ChatProxy` that interfaces with an AI model. This setup suggests a sophisticated plugin that leverages AI for code modification tasks. Based on this, a feature +development roadmap can be structured as follows: #### Phase 1: Core Functionality Enhancement -- **1.1 Improve AI Model Integration:** Enhance the integration with the AI model to support more languages and more complex code editing tasks. -- **1.2 Expand Language Support:** Increase the number of programming languages the plugin can handle, focusing on popular languages such as Python, JavaScript, and C++. -- **1.3 User Interface Improvements:** Develop a more intuitive and responsive UI for the plugin, making it easier for users to input their instructions and view the edited code. +- **1.1 Improve AI Model Integration:** Enhance the integration with the AI model to support more languages and more complex code editing tasks. +- **1.2 Expand Language Support:** Increase the number of programming languages the plugin can handle, focusing on popular languages such as Python, JavaScript, + and C++. +- **1.3 User Interface Improvements:** Develop a more intuitive and responsive UI for the plugin, making it easier for users to input their instructions and + view the edited code. #### Phase 2: User Experience and Efficiency + - **2.1 Instruction History Management:** Implement a more sophisticated history management system that allows users to view, edit, and reuse past instructions. - **2.2 Real-time Preview:** Introduce a feature that allows users to preview the changes in real-time before finalizing the edit. -- **2.3 Customizable AI Parameters:** Provide advanced settings for users to customize AI parameters such as temperature and model choice, catering to different editing styles and preferences. - +- **2.3 Customizable AI Parameters:** Provide advanced settings for users to customize AI parameters such as temperature and model choice, catering to different + editing styles and preferences. #### Phase 3: Collaboration and Integration -- **3.1 Version Control Integration:** Ensure seamless integration with version control systems like Git, allowing users to directly commit edited code from the plugin. -- **3.2 Team Collaboration Features:** Add features that enable team members to share and collaborate on code edits within the plugin environment. -- **3.3 External Tools Integration:** Facilitate integration with external tools and services, such as code formatters and linters, to further enhance the code editing process. +- **3.1 Version Control Integration:** Ensure seamless integration with version control systems like Git, allowing users to directly commit edited code from the + plugin. +- **3.2 Team Collaboration Features:** Add features that enable team members to share and collaborate on code edits within the plugin environment. +- **3.3 External Tools Integration:** Facilitate integration with external tools and services, such as code formatters and linters, to further enhance the code + editing process. #### Phase 4: Intelligence and Learning -- **4.1 Learning from Edits:** Implement machine learning algorithms that allow the AI to learn from user edits over time, improving suggestion quality. -- **4.2 Context-Aware Editing Suggestions:** Develop context-aware editing capabilities that consider the broader scope of the project and the specific task at hand. -- **4.3 Personalized User Experience:** Introduce personalization features that adapt the plugin’s behavior and suggestions based on individual user preferences and coding styles. +- **4.1 Learning from Edits:** Implement machine learning algorithms that allow the AI to learn from user edits over time, improving suggestion quality. +- **4.2 Context-Aware Editing Suggestions:** Develop context-aware editing capabilities that consider the broader scope of the project and the specific task at + hand. +- **4.3 Personalized User Experience:** Introduce personalization features that adapt the plugin’s behavior and suggestions based on individual user preferences + and coding styles. #### Phase 5: Security and Reliability + - **5.1 Security Enhancements:** Strengthen security measures to protect user data and code, especially when integrating with external AI services. -- **5.2 Reliability Improvements:** Focus on improving the reliability and performance of the plugin, ensuring it can handle large projects and complex editing tasks without significant lag or errors. +- **5.2 Reliability Improvements:** Focus on improving the reliability and performance of the plugin, ensuring it can handle large projects and complex editing + tasks without significant lag or errors. - **5.3 Offline Functionality:** Explore possibilities for offline functionality, allowing users to make basic edits without an active internet connection. - #### Phase 6: Community and Feedback + - **6.1 User Feedback System:** Implement a system for collecting and analyzing user feedback to guide future development priorities. -- **6.2 Community Contributions:** Encourage community contributions by making the plugin open source or providing an API for third-party extensions and plugins. +- **6.2 Community Contributions:** Encourage community contributions by making the plugin open source or providing an API for third-party extensions and + plugins. - **6.3 Documentation and Tutorials:** Create comprehensive documentation and tutorials to help users make the most of the plugin’s features. -This roadmap outlines a strategic approach to developing the plugin, focusing on enhancing its core functionality, improving user experience, and ensuring security and reliability, while also fostering community engagement and feedback. +This roadmap outlines a strategic approach to developing the plugin, focusing on enhancing its core functionality, improving user experience, and ensuring +security and reliability, while also fostering community engagement and feedback. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\CommentsAction.kt -The `CommentsAction` class is part of a larger project aimed at enhancing code readability and understanding through automated comments. This class leverages an AI model, via a `ChatProxy`, to add explanatory comments to code selections. The roadmap for developing and enhancing this feature can be structured into several key phases, each focusing on specific aspects of functionality, user experience, and integration. - +The `CommentsAction` class is part of a larger project aimed at enhancing code readability and understanding through automated comments. This class leverages an +AI model, via a `ChatProxy`, to add explanatory comments to code selections. The roadmap for developing and enhancing this feature can be structured into +several key phases, each focusing on specific aspects of functionality, user experience, and integration. #### Phase 1: Core Functionality Development + - **Task 1.1:** Implement the basic structure of the `CommentsAction` class, enabling it to interact with the `ChatProxy` for processing code selections. - **Task 1.2:** Develop the `CommentsAction_VirtualAPI` interface and its `editCode` method to define how code is sent to and received from the AI model. - **Task 1.3:** Ensure the `processSelection` method can accurately send selected code to the AI model and receive commented code in return. - **Task 1.4:** Implement language support checks to ensure the feature is only used with supported programming languages, enhancing reliability. - #### Phase 2: User Experience and Usability Enhancements -- **Task 2.1:** Create a user-friendly configuration interface for `CommentsAction`, allowing users to customize settings such as AI temperature and preferred human language. + +- **Task 2.1:** Create a user-friendly configuration interface for `CommentsAction`, allowing users to customize settings such as AI temperature and preferred + human language. - **Task 2.2:** Develop a feedback mechanism for users to report inaccuracies in comments, contributing to continuous improvement of the AI model. - **Task 2.3:** Integrate with IDE notifications to inform users about the status of their comment generation requests (e.g., processing, success, failure). - #### Phase 3: Performance Optimization and Error Handling + - **Task 3.1:** Optimize the interaction with the `ChatProxy` to reduce latency and improve the responsiveness of the comment generation feature. - **Task 3.2:** Implement comprehensive error handling to manage issues such as network failures, unsupported code selections, and API limits. - **Task 3.3:** Add caching mechanisms where appropriate to minimize redundant requests for similar code selections, conserving API usage and enhancing speed. - #### Phase 4: Advanced Features and Integration + - **Task 4.1:** Explore and integrate advanced AI model options to improve the quality and relevance of generated comments. - **Task 4.2:** Develop an option for bulk processing, allowing users to add comments to entire files or projects with a single action. - **Task 4.3:** Investigate the possibility of custom AI training with user-specific codebases to enhance comment accuracy and context relevance. - #### Phase 5: Testing, Documentation, and Release + - **Task 5.1:** Conduct thorough testing, including unit tests, integration tests, and user acceptance testing, to ensure reliability and usability. - **Task 5.2:** Prepare comprehensive documentation covering setup, usage, customization options, and troubleshooting. - **Task 5.3:** Plan and execute a phased release strategy, starting with a beta release to gather user feedback before a full rollout. - #### Phase 6: Feedback Loop and Continuous Improvement + - **Task 6.1:** Establish a system for collecting user feedback and metrics on the feature's performance and accuracy. - **Task 6.2:** Regularly review feedback and performance data to identify areas for improvement. - **Task 6.3:** Implement updates and enhancements based on user feedback and technological advancements in AI. -This roadmap outlines a structured approach to developing the `CommentsAction` feature, from initial functionality through to advanced integration and continuous improvement, ensuring the tool remains valuable, effective, and user-friendly. +This roadmap outlines a structured approach to developing the `CommentsAction` feature, from initial functionality through to advanced integration and +continuous improvement, ensuring the tool remains valuable, effective, and user-friendly. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\BaseAction.kt -Creating a feature development roadmap for the `BaseAction` class and its associated functionalities involves outlining the planned enhancements, improvements, and new features that will be added over time. This roadmap will guide the development process, ensuring that the project evolves in a way that meets users' needs and leverages new technologies effectively. Here's a proposed roadmap: - +Creating a feature development roadmap for the `BaseAction` class and its associated functionalities involves outlining the planned enhancements, improvements, +and new features that will be added over time. This roadmap will guide the development process, ensuring that the project evolves in a way that meets users' +needs and leverages new technologies effectively. Here's a proposed roadmap: #### Phase 1: Foundation and Stability -- **Refinement of the BaseAction Class**: Focus on ensuring that the `BaseAction` class is robust, with clear documentation and examples for extending it. This includes refining the abstract methods and ensuring that the class can be easily extended for various actions within the IDE. -- **Enhanced Error Handling**: Improve error handling and logging within actions to provide clearer feedback to developers when something goes wrong. This could involve more descriptive error messages and suggestions for resolution. -- **Performance Optimization**: Analyze and optimize the performance of actions, especially focusing on reducing the impact on the IDE's responsiveness. +- **Refinement of the BaseAction Class**: Focus on ensuring that the `BaseAction` class is robust, with clear documentation and examples for extending it. This + includes refining the abstract methods and ensuring that the class can be easily extended for various actions within the IDE. +- **Enhanced Error Handling**: Improve error handling and logging within actions to provide clearer feedback to developers when something goes wrong. This could + involve more descriptive error messages and suggestions for resolution. +- **Performance Optimization**: Analyze and optimize the performance of actions, especially focusing on reducing the impact on the IDE's responsiveness. #### Phase 2: Integration and Expansion -- **Integration with Other Services**: Expand the `BaseAction` class to integrate more seamlessly with other services and APIs, both internal and external to the IDE. This could include version control systems, build tools, and external APIs like OpenAI. -- **UI Improvements**: Enhance the UI toolkit (`UITools`) for actions, making it easier to create consistent and user-friendly interfaces for action inputs and outputs. This could involve new dialogs, notifications, and input validation methods. -- **Asynchronous Execution Support**: Develop support for executing actions asynchronously, allowing for long-running tasks to be performed without blocking the IDE. This includes managing and displaying the status of these tasks to the user. +- **Integration with Other Services**: Expand the `BaseAction` class to integrate more seamlessly with other services and APIs, both internal and external to + the IDE. This could include version control systems, build tools, and external APIs like OpenAI. +- **UI Improvements**: Enhance the UI toolkit (`UITools`) for actions, making it easier to create consistent and user-friendly interfaces for action inputs and + outputs. This could involve new dialogs, notifications, and input validation methods. +- **Asynchronous Execution Support**: Develop support for executing actions asynchronously, allowing for long-running tasks to be performed without blocking the + IDE. This includes managing and displaying the status of these tasks to the user. #### Phase 3: Intelligence and Automation -- **AI-Assisted Development**: Leverage the `IdeaOpenAIClient` and other AI technologies to introduce intelligent features such as code suggestions, automated refactoring, and bug detection within actions. -- **Automated Testing and Quality Assurance**: Implement automated testing frameworks for actions, ensuring that they work as expected across different environments and IDE versions. This includes unit tests, integration tests, and UI tests. -- **Customization and Extensibility**: Provide mechanisms for developers to customize and extend the functionality of actions more easily. This could involve plugin extensions, user-defined scripts, or a marketplace for sharing actions. +- **AI-Assisted Development**: Leverage the `IdeaOpenAIClient` and other AI technologies to introduce intelligent features such as code suggestions, automated + refactoring, and bug detection within actions. +- **Automated Testing and Quality Assurance**: Implement automated testing frameworks for actions, ensuring that they work as expected across different + environments and IDE versions. This includes unit tests, integration tests, and UI tests. +- **Customization and Extensibility**: Provide mechanisms for developers to customize and extend the functionality of actions more easily. This could involve + plugin extensions, user-defined scripts, or a marketplace for sharing actions. #### Phase 4: Community and Collaboration -- **Documentation and Tutorials**: Create comprehensive documentation, tutorials, and sample projects to help developers understand how to use and extend actions effectively. -- **Community Engagement**: Establish a community forum or platform for developers to share their custom actions, seek help, and collaborate on projects. This could also involve regular hackathons or competitions. -- **Feedback Loop**: Implement a system for collecting user feedback on actions, including feature requests and bug reports. Use this feedback to inform the development roadmap and prioritize new features. +- **Documentation and Tutorials**: Create comprehensive documentation, tutorials, and sample projects to help developers understand how to use and extend + actions effectively. +- **Community Engagement**: Establish a community forum or platform for developers to share their custom actions, seek help, and collaborate on projects. This + could also involve regular hackathons or competitions. +- **Feedback Loop**: Implement a system for collecting user feedback on actions, including feature requests and bug reports. Use this feedback to inform the + development roadmap and prioritize new features. #### Phase 5: Future-Proofing and Innovation + - **Adaptation to New Technologies**: Continuously monitor and integrate new technologies and IDE features to keep the actions relevant and powerful. -- **Exploration of New IDEs**: Explore the possibility of adapting the `BaseAction` framework for use in other IDEs or code editors, broadening the reach and impact of the project. -- **Innovative Features**: Encourage the exploration of innovative features that could redefine how developers interact with their IDE, such as virtual reality interfaces, advanced code analysis tools, or machine learning-based code generation. +- **Exploration of New IDEs**: Explore the possibility of adapting the `BaseAction` framework for use in other IDEs or code editors, broadening the reach and + impact of the project. +- **Innovative Features**: Encourage the exploration of innovative features that could redefine how developers interact with their IDE, such as virtual reality + interfaces, advanced code analysis tools, or machine learning-based code generation. -This roadmap is intended to be iterative, with each phase building upon the last. Feedback from users and contributors should be continuously incorporated to ensure that the project remains relevant and valuable to the developer community. +This roadmap is intended to be iterative, with each phase building upon the last. Feedback from users and contributors should be continuously incorporated to +ensure that the project remains relevant and valuable to the developer community. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\DocAction.kt -The `DocAction` class is designed to enhance code documentation by automatically generating detailed documentation prefixes for code blocks. This feature leverages a virtual API, `DocAction_VirtualAPI`, to process code snippets and generate documentation in the specified human language. The roadmap for further developing this feature can be outlined in several stages, focusing on expanding capabilities, improving user experience, and ensuring robustness and scalability. - +The `DocAction` class is designed to enhance code documentation by automatically generating detailed documentation prefixes for code blocks. This feature +leverages a virtual API, `DocAction_VirtualAPI`, to process code snippets and generate documentation in the specified human language. The roadmap for further +developing this feature can be outlined in several stages, focusing on expanding capabilities, improving user experience, and ensuring robustness and +scalability. #### Phase 1: Core Functionality Enhancement -- **Refine Documentation Quality**: Improve the AI model's ability to generate more accurate and context-aware documentation. This could involve training the model on a larger dataset or fine-tuning it with more specific examples. -- **Support for More Languages**: Extend the feature to support additional programming languages beyond Kotlin, starting with popular languages such as Java, Python, and JavaScript. -- **Customization Options**: Allow users to customize the style and verbosity of the generated documentation through the plugin settings. +- **Refine Documentation Quality**: Improve the AI model's ability to generate more accurate and context-aware documentation. This could involve training the + model on a larger dataset or fine-tuning it with more specific examples. +- **Support for More Languages**: Extend the feature to support additional programming languages beyond Kotlin, starting with popular languages such as Java, + Python, and JavaScript. +- **Customization Options**: Allow users to customize the style and verbosity of the generated documentation through the plugin settings. #### Phase 2: User Experience Improvements -- **Interactive Documentation Editing**: Implement a UI within the IDE that allows users to interactively edit the generated documentation before finalizing it. This could include suggestions for different wording or additional details to include. -- **Integration with Code Analysis Tools**: Integrate the documentation generation feature with existing code analysis tools within the IDE to automatically highlight sections of code that lack sufficient documentation. -- **Performance Optimization**: Optimize the performance of the documentation generation process to ensure it runs smoothly, even in large projects. +- **Interactive Documentation Editing**: Implement a UI within the IDE that allows users to interactively edit the generated documentation before finalizing it. + This could include suggestions for different wording or additional details to include. +- **Integration with Code Analysis Tools**: Integrate the documentation generation feature with existing code analysis tools within the IDE to automatically + highlight sections of code that lack sufficient documentation. +- **Performance Optimization**: Optimize the performance of the documentation generation process to ensure it runs smoothly, even in large projects. #### Phase 3: Advanced Features -- **Contextual Documentation**: Develop the ability to generate documentation that not only describes what a code block does but also why it does it, based on the broader context of the codebase. -- **Documentation Consistency Checker**: Implement a feature that checks the consistency of documentation across the codebase, ensuring that similar functions or methods are described in a consistent manner. -- **Automatic Documentation Updates**: Create a mechanism to automatically update documentation when the corresponding code is changed, ensuring that the documentation remains accurate over time. +- **Contextual Documentation**: Develop the ability to generate documentation that not only describes what a code block does but also why it does it, based on + the broader context of the codebase. +- **Documentation Consistency Checker**: Implement a feature that checks the consistency of documentation across the codebase, ensuring that similar functions + or methods are described in a consistent manner. +- **Automatic Documentation Updates**: Create a mechanism to automatically update documentation when the corresponding code is changed, ensuring that the + documentation remains accurate over time. #### Phase 4: Scalability and Robustness -- **Scalability Improvements**: Ensure that the documentation generation feature can scale to accommodate large projects with thousands of files without significant performance degradation. -- **Robustness and Error Handling**: Improve error handling to gracefully manage failures in the documentation generation process, such as API timeouts or unexpected input. -- **Security Enhancements**: Strengthen security measures to protect the code and documentation data, especially when using cloud-based APIs for processing. +- **Scalability Improvements**: Ensure that the documentation generation feature can scale to accommodate large projects with thousands of files without + significant performance degradation. +- **Robustness and Error Handling**: Improve error handling to gracefully manage failures in the documentation generation process, such as API timeouts or + unexpected input. +- **Security Enhancements**: Strengthen security measures to protect the code and documentation data, especially when using cloud-based APIs for processing. #### Phase 5: Community and Open Source -- **Open Source Contributions**: Open source part of the plugin to allow the community to contribute to its development, including adding support for new languages or improving the AI model. -- **Documentation and Tutorials**: Develop comprehensive documentation and tutorials to help users get the most out of the feature, including best practices for writing code that is easier to document automatically. + +- **Open Source Contributions**: Open source part of the plugin to allow the community to contribute to its development, including adding support for new + languages or improving the AI model. +- **Documentation and Tutorials**: Develop comprehensive documentation and tutorials to help users get the most out of the feature, including best practices for + writing code that is easier to document automatically. - **Feedback Mechanism**: Implement a feedback mechanism within the plugin to allow users to report issues or suggest improvements directly from the IDE. -This roadmap outlines a comprehensive approach to developing the `DocAction` feature, focusing on delivering immediate value to users while laying the groundwork for more sophisticated capabilities in the future. +This roadmap outlines a comprehensive approach to developing the `DocAction` feature, focusing on delivering immediate value to users while laying the +groundwork for more sophisticated capabilities in the future. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\DescribeAction.kt -The `DescribeAction` class is part of a larger project aimed at enhancing code understanding and documentation through automated descriptions. The development roadmap for this feature and its integration into the broader system can be outlined in several phases, focusing on expanding capabilities, improving accuracy, and enhancing user experience. - +The `DescribeAction` class is part of a larger project aimed at enhancing code understanding and documentation through automated descriptions. The development +roadmap for this feature and its integration into the broader system can be outlined in several phases, focusing on expanding capabilities, improving accuracy, +and enhancing user experience. #### Phase 1: Initial Implementation and Testing -- **Development of `DescribeAction` Class**: Implement the initial version of the `DescribeAction` class, which includes the ability to select code and request a description through a virtual API. -- **Integration with Virtual API**: Establish a connection with `ChatProxy` to utilize a virtual API for generating code descriptions. -- **Basic Functionality Testing**: Conduct internal testing to ensure the basic functionalities, such as code selection and description retrieval, work as expected. +- **Development of `DescribeAction` Class**: Implement the initial version of the `DescribeAction` class, which includes the ability to select code and request + a description through a virtual API. +- **Integration with Virtual API**: Establish a connection with `ChatProxy` to utilize a virtual API for generating code descriptions. +- **Basic Functionality Testing**: Conduct internal testing to ensure the basic functionalities, such as code selection and description retrieval, work as + expected. #### Phase 2: Feature Enhancement and Optimization -- **Language Support Expansion**: Expand the support for different programming languages by enhancing the `describeCode` method to accurately handle a wider array of computer languages. -- **Description Quality Improvement**: Implement advanced algorithms or utilize more sophisticated models in the virtual API to improve the quality and accuracy of generated descriptions. -- **Performance Optimization**: Optimize the performance of the `DescribeAction` feature, focusing on reducing latency in fetching descriptions and improving the efficiency of the underlying code. +- **Language Support Expansion**: Expand the support for different programming languages by enhancing the `describeCode` method to accurately handle a wider + array of computer languages. +- **Description Quality Improvement**: Implement advanced algorithms or utilize more sophisticated models in the virtual API to improve the quality and accuracy + of generated descriptions. +- **Performance Optimization**: Optimize the performance of the `DescribeAction` feature, focusing on reducing latency in fetching descriptions and improving + the efficiency of the underlying code. #### Phase 3: User Interface and Experience -- **Integration with IDEs**: Ensure seamless integration with popular Integrated Development Environments (IDEs) like IntelliJ IDEA, enhancing the user experience by providing easy access to the feature within the coding environment. -- **Customization Options**: Develop settings and customization options allowing users to adjust the verbosity, language, and format of the generated descriptions according to their preferences. -- **Feedback Mechanism**: Implement a feedback mechanism for users to report inaccuracies or suggest improvements in generated descriptions, contributing to continuous learning and enhancement of the virtual API. +- **Integration with IDEs**: Ensure seamless integration with popular Integrated Development Environments (IDEs) like IntelliJ IDEA, enhancing the user + experience by providing easy access to the feature within the coding environment. +- **Customization Options**: Develop settings and customization options allowing users to adjust the verbosity, language, and format of the generated + descriptions according to their preferences. +- **Feedback Mechanism**: Implement a feedback mechanism for users to report inaccuracies or suggest improvements in generated descriptions, contributing to + continuous learning and enhancement of the virtual API. #### Phase 4: Advanced Features and Capabilities -- **Context-Aware Descriptions**: Enhance the `DescribeAction` feature to generate context-aware descriptions, considering the broader scope of the codebase and its functionalities. -- **Interactive Descriptions**: Explore the possibility of making the descriptions interactive, allowing users to request further clarifications or additional details on specific parts of the code. -- **Integration with Documentation Tools**: Develop integrations with documentation tools and platforms, enabling the automatic generation and updating of technical documentation based on the code descriptions. +- **Context-Aware Descriptions**: Enhance the `DescribeAction` feature to generate context-aware descriptions, considering the broader scope of the codebase and + its functionalities. +- **Interactive Descriptions**: Explore the possibility of making the descriptions interactive, allowing users to request further clarifications or additional + details on specific parts of the code. +- **Integration with Documentation Tools**: Develop integrations with documentation tools and platforms, enabling the automatic generation and updating of + technical documentation based on the code descriptions. #### Phase 5: Evaluation and Iteration -- **User Testing and Feedback Collection**: Conduct extensive user testing to collect feedback on the usability, accuracy, and overall satisfaction with the `DescribeAction` feature. -- **Iterative Improvement**: Based on user feedback and performance metrics, iteratively improve the feature, focusing on areas highlighted by users and analytics. -- **Long-Term Support and Updates**: Establish a plan for long-term support and regular updates to the `DescribeAction` feature, ensuring it remains compatible with new IDE versions and programming languages. -This roadmap outlines a comprehensive approach to developing and enhancing the `DescribeAction` feature, from its initial implementation to advanced capabilities and user-focused improvements. Each phase builds upon the previous one, aiming to create a robust, user-friendly tool that significantly aids in code understanding and documentation. +- **User Testing and Feedback Collection**: Conduct extensive user testing to collect feedback on the usability, accuracy, and overall satisfaction with the + `DescribeAction` feature. +- **Iterative Improvement**: Based on user feedback and performance metrics, iteratively improve the feature, focusing on areas highlighted by users and + analytics. +- **Long-Term Support and Updates**: Establish a plan for long-term support and regular updates to the `DescribeAction` feature, ensuring it remains compatible + with new IDE versions and programming languages. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\ImplementStubAction.kt +This roadmap outlines a comprehensive approach to developing and enhancing the `DescribeAction` feature, from its initial implementation to advanced +capabilities and user-focused improvements. Each phase builds upon the previous one, aiming to create a robust, user-friendly tool that significantly aids in +code understanding and documentation. -The `ImplementStubAction` class is part of a larger project aimed at enhancing code development through automation and AI assistance. To further develop this project, a structured feature development roadmap is essential. The roadmap will outline the planned enhancements, new features, and improvements, divided into phases for better management and clarity. +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\ImplementStubAction.kt +The `ImplementStubAction` class is part of a larger project aimed at enhancing code development through automation and AI assistance. To further develop this +project, a structured feature development roadmap is essential. The roadmap will outline the planned enhancements, new features, and improvements, divided into +phases for better management and clarity. #### Phase 1: Core Functionality Enhancement -- **Refine AI Proxy Integration**: Improve the integration with `ChatProxy` to ensure more stable and efficient communication with the AI model. This includes optimizing the API calls and handling exceptions more gracefully. -- **Expand Language Support**: Currently, the action checks if the language is supported and excludes `ComputerLanguage.Text`. Expand support to more programming languages and include a mechanism to easily update this list as new languages are supported by the underlying AI model. -- **Improve Selection Algorithm**: Enhance the `defaultSelection` method to more intelligently select code snippets for stub implementation, possibly incorporating AI to suggest the most relevant sections of code needing implementation. - +- **Refine AI Proxy Integration**: Improve the integration with `ChatProxy` to ensure more stable and efficient communication with the AI model. This includes + optimizing the API calls and handling exceptions more gracefully. +- **Expand Language Support**: Currently, the action checks if the language is supported and excludes `ComputerLanguage.Text`. Expand support to more + programming languages and include a mechanism to easily update this list as new languages are supported by the underlying AI model. +- **Improve Selection Algorithm**: Enhance the `defaultSelection` method to more intelligently select code snippets for stub implementation, possibly + incorporating AI to suggest the most relevant sections of code needing implementation. #### Phase 2: User Experience and Usability -- **Configurable Settings in UI**: Develop a user interface within the settings to allow users to configure the `ImplementStubAction` parameters, such as default human and computer languages, temperature settings for the AI, and other preferences. -- **Feedback Mechanism**: Implement a feedback loop where users can rate the suggestions provided by the AI and suggest improvements. This data can be invaluable for training the AI model for better accuracy. -- **Documentation and Help**: Create comprehensive documentation and in-app help guides to assist users in understanding how to use the `ImplementStubAction` effectively, including troubleshooting common issues. - +- **Configurable Settings in UI**: Develop a user interface within the settings to allow users to configure the `ImplementStubAction` parameters, such as + default human and computer languages, temperature settings for the AI, and other preferences. +- **Feedback Mechanism**: Implement a feedback loop where users can rate the suggestions provided by the AI and suggest improvements. This data can be + invaluable for training the AI model for better accuracy. +- **Documentation and Help**: Create comprehensive documentation and in-app help guides to assist users in understanding how to use the `ImplementStubAction` + effectively, including troubleshooting common issues. #### Phase 3: Advanced Features and Integration -- **Context-Aware Suggestions**: Enhance the AI model to consider more context around the selected code snippet, including the entire file or related modules, to provide more accurate and useful code implementations. -- **Collaboration Tools**: Introduce features that allow teams to share and collaborate on AI-generated code suggestions, including version control system integration. -- **Performance Optimization**: Focus on optimizing the performance of the action, ensuring that it runs smoothly even in large projects with minimal impact on the IDE's performance. - +- **Context-Aware Suggestions**: Enhance the AI model to consider more context around the selected code snippet, including the entire file or related modules, + to provide more accurate and useful code implementations. +- **Collaboration Tools**: Introduce features that allow teams to share and collaborate on AI-generated code suggestions, including version control system + integration. +- **Performance Optimization**: Focus on optimizing the performance of the action, ensuring that it runs smoothly even in large projects with minimal impact on + the IDE's performance. #### Phase 4: Analytics and Improvement -- **Usage Analytics**: Implement analytics to gather anonymized data on how the `ImplementStubAction` is used, which features are most popular, and what issues users encounter most frequently. +- **Usage Analytics**: Implement analytics to gather anonymized data on how the `ImplementStubAction` is used, which features are most popular, and what issues + users encounter most frequently. - **Continuous Learning**: Use the feedback and analytics data to continuously improve the AI model, focusing on areas where users face the most challenges. -- **Expand VirtualAPI Capabilities**: Explore and implement additional functionalities through the `VirtualAPI`, such as refactoring code, generating documentation, or even creating test cases based on the implemented stubs. - +- **Expand VirtualAPI Capabilities**: Explore and implement additional functionalities through the `VirtualAPI`, such as refactoring code, generating + documentation, or even creating test cases based on the implemented stubs. #### Phase 5: Community and Open Source -- **Open Source Contributions**: Open up parts of the project for community contributions, especially around language support, documentation, and user interface enhancements. -- **Plugin Ecosystem**: Develop an ecosystem around the project that allows other developers to create plugins or extensions, enhancing the functionality of the `ImplementStubAction` or integrating it with other tools and services. -- **Community Engagement**: Foster a community around the project through forums, social media, and developer events to gather more feedback, ideas, and contributions. +- **Open Source Contributions**: Open up parts of the project for community contributions, especially around language support, documentation, and user interface + enhancements. +- **Plugin Ecosystem**: Develop an ecosystem around the project that allows other developers to create plugins or extensions, enhancing the functionality of the + `ImplementStubAction` or integrating it with other tools and services. +- **Community Engagement**: Foster a community around the project through forums, social media, and developer events to gather more feedback, ideas, and + contributions. -This roadmap is designed to be iterative, with each phase building upon the successes and lessons of the previous ones. Feedback from users and contributors will be crucial at every step to ensure that the project evolves in a direction that adds the most value to its users. +This roadmap is designed to be iterative, with each phase building upon the successes and lessons of the previous ones. Feedback from users and contributors +will be crucial at every step to ensure that the project evolves in a direction that adds the most value to its users. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\PasteAction.kt -Developing a feature, especially for a software project like the one described in the provided code, involves a series of steps from initial conception to final deployment. Below is a detailed feature development roadmap tailored to the context of enhancing or creating new functionalities within the `PasteAction` class, which is part of a larger project aimed at integrating AI-powered code conversion into an IDE (Integrated Development Environment). - +Developing a feature, especially for a software project like the one described in the provided code, involves a series of steps from initial conception to final +deployment. Below is a detailed feature development roadmap tailored to the context of enhancing or creating new functionalities within the `PasteAction` class, +which is part of a larger project aimed at integrating AI-powered code conversion into an IDE (Integrated Development Environment). #### 1. Conceptualization and Planning -- **Idea Generation:** Brainstorm potential enhancements or new features that could be added to the `PasteAction` class, focusing on improving user experience, expanding language support, or optimizing the conversion process. -- **Feasibility Study:** Assess the technical feasibility and potential impact of the proposed features. This includes evaluating the capabilities of the `ChatProxy` and `VirtualAPI` for new functionalities. -- **Requirement Analysis:** Define clear, detailed requirements for the chosen enhancements. This should include user stories, expected behavior, and specific outcomes. +- **Idea Generation:** Brainstorm potential enhancements or new features that could be added to the `PasteAction` class, focusing on improving user experience, + expanding language support, or optimizing the conversion process. +- **Feasibility Study:** Assess the technical feasibility and potential impact of the proposed features. This includes evaluating the capabilities of the + `ChatProxy` and `VirtualAPI` for new functionalities. +- **Requirement Analysis:** Define clear, detailed requirements for the chosen enhancements. This should include user stories, expected behavior, and specific + outcomes. #### 2. Design -- **Architecture Design:** Outline the architectural changes or additions needed to support the new features. This may involve modifying the `VirtualAPI` interface or integrating additional services. -- **UI/UX Design:** If the feature impacts the user interface, create mockups or prototypes to visualize the changes. For backend features, detail the user flow and interaction with the new functionality. +- **Architecture Design:** Outline the architectural changes or additions needed to support the new features. This may involve modifying the `VirtualAPI` + interface or integrating additional services. +- **UI/UX Design:** If the feature impacts the user interface, create mockups or prototypes to visualize the changes. For backend features, detail the user flow + and interaction with the new functionality. #### 3. Development + - **Environment Setup:** Ensure the development environment is prepared, including access to necessary APIs, libraries, and tools. -- **Coding:** Begin coding the new features or enhancements. For the `PasteAction` class, this could involve adding new methods, modifying existing logic, or integrating with additional APIs. +- **Coding:** Begin coding the new features or enhancements. For the `PasteAction` class, this could involve adding new methods, modifying existing logic, or + integrating with additional APIs. - **Unit Testing:** Write and run unit tests to ensure each component of the feature works as expected in isolation. - #### 4. Integration and Testing + - **Integration:** Merge the new feature with the existing codebase, ensuring compatibility and proper interaction between components. - **Functional Testing:** Conduct thorough testing to verify that the feature meets all requirements and behaves as expected within the application. - **Performance Testing:** Evaluate the performance of the new feature, particularly if it involves processing large amounts of data or complex conversions. - #### 5. Deployment + - **Beta Release:** Optionally, release the feature to a limited user base to gather early feedback and identify any unforeseen issues. - **Deployment:** Deploy the feature to the production environment, making it available to all users. - **Monitoring:** Closely monitor the feature for any issues or unexpected behavior following the deployment. - #### 6. Feedback and Iteration + - **User Feedback:** Collect and analyze user feedback to identify areas for improvement or additional features. - **Iterative Development:** Based on feedback and performance data, make necessary adjustments or enhancements to the feature. - **Documentation:** Update project documentation to reflect the new feature, including user guides, API documentation, and developer notes. - #### 7. Maintenance + - **Bug Fixes:** Address any bugs or issues that arise post-deployment in a timely manner. - **Updates:** Keep the feature up-to-date with new developments in related technologies or changes in user requirements. -This roadmap provides a structured approach to developing new features or enhancements for the `PasteAction` class, ensuring that the end result is well-designed, thoroughly tested, and provides real value to the users. +This roadmap provides a structured approach to developing new features or enhancements for the `PasteAction` class, ensuring that the end result is +well-designed, thoroughly tested, and provides real value to the users. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\InsertImplementationAction.kt - #### Feature Development Roadmap for InsertImplementationAction -The `InsertImplementationAction` class is designed to enhance the coding experience by automatically generating code implementations based on comments or selected text within an IDE. This roadmap outlines the planned features and improvements to make this tool more robust, user-friendly, and versatile. - +The `InsertImplementationAction` class is designed to enhance the coding experience by automatically generating code implementations based on comments or +selected text within an IDE. This roadmap outlines the planned features and improvements to make this tool more robust, user-friendly, and versatile. ##### Phase 1: Core Functionality Enhancements 1. **Improved Code Generation Accuracy** - - Implement advanced NLP models to better understand the context and intent behind comments or selected text. - - Integrate with multiple code generation APIs to compare and choose the best-generated code snippet. + +- Implement advanced NLP models to better understand the context and intent behind comments or selected text. +- Integrate with multiple code generation APIs to compare and choose the best-generated code snippet. 2. **Support for More Programming Languages** - - Extend the current support to include more programming languages, focusing on those most requested by the community. - - Develop language-specific plugins to handle idiomatic nuances better. + +- Extend the current support to include more programming languages, focusing on those most requested by the community. +- Develop language-specific plugins to handle idiomatic nuances better. 3. **Enhanced Context Understanding** - - Improve the extraction and interpretation of the surrounding code context to generate more relevant code snippets. - - Use the entire file or project context when generating code to ensure consistency and adherence to project standards. +- Improve the extraction and interpretation of the surrounding code context to generate more relevant code snippets. +- Use the entire file or project context when generating code to ensure consistency and adherence to project standards. ##### Phase 2: User Experience Improvements 1. **Configurable Preferences** - - Allow users to set preferences for code style, documentation, and error handling. - - Enable project-specific configurations to maintain consistency across team projects. + +- Allow users to set preferences for code style, documentation, and error handling. +- Enable project-specific configurations to maintain consistency across team projects. 2. **Interactive Code Generation** - - Introduce an interactive mode where users can guide the code generation process through options or corrections. - - Implement feedback loops where the tool learns from user corrections to improve future suggestions. + +- Introduce an interactive mode where users can guide the code generation process through options or corrections. +- Implement feedback loops where the tool learns from user corrections to improve future suggestions. 3. **Integration with Development Environments** - - Develop plugins for popular IDEs (e.g., VSCode, IntelliJ IDEA) to provide seamless integration. - - Ensure compatibility with cloud-based development environments. +- Develop plugins for popular IDEs (e.g., VSCode, IntelliJ IDEA) to provide seamless integration. +- Ensure compatibility with cloud-based development environments. ##### Phase 3: Collaboration and Sharing 1. **Code Snippet Sharing** - - Create a platform for users to share and discover code snippets generated by the tool. - - Implement tagging and categorization to make it easier to find relevant snippets. + +- Create a platform for users to share and discover code snippets generated by the tool. +- Implement tagging and categorization to make it easier to find relevant snippets. 2. **Team Collaboration Features** - - Enable teams to share a common configuration and preferences for code generation. - - Provide mechanisms for reviewing and approving generated code before it is merged into the codebase. + +- Enable teams to share a common configuration and preferences for code generation. +- Provide mechanisms for reviewing and approving generated code before it is merged into the codebase. 3. **Community-Driven Improvements** - - Open source the tool or parts of it to allow the community to contribute improvements and new features. - - Set up a system for users to report issues, request features, and contribute to the tool's development. +- Open source the tool or parts of it to allow the community to contribute improvements and new features. +- Set up a system for users to report issues, request features, and contribute to the tool's development. ##### Phase 4: Advanced Features and Integrations 1. **AI-Powered Refactoring** - - Use AI to suggest refactoring opportunities in existing code based on best practices and recent advancements. - - Implement automated refactoring with user approval to improve code quality and maintainability. + +- Use AI to suggest refactoring opportunities in existing code based on best practices and recent advancements. +- Implement automated refactoring with user approval to improve code quality and maintainability. 2. **Integration with Code Analysis Tools** - - Connect with static code analysis tools to ensure generated code meets quality standards. - - Use feedback from code analysis to improve the code generation models. + +- Connect with static code analysis tools to ensure generated code meets quality standards. +- Use feedback from code analysis to improve the code generation models. 3. **Custom Model Training** - - Allow users or organizations to train custom models on their codebases to tailor suggestions more closely to their coding styles and practices. - - Implement privacy-preserving techniques to ensure codebase confidentiality during model training. -This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The goal is to continuously improve the `InsertImplementationAction` tool to meet the evolving needs of developers and teams. +- Allow users or organizations to train custom models on their codebases to tailor suggestions more closely to their coding styles and practices. +- Implement privacy-preserving techniques to ensure codebase confidentiality during model training. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\RenameVariablesAction.kt +This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The goal is to continuously improve the +`InsertImplementationAction` tool to meet the evolving needs of developers and teams. -Developing a feature like the `RenameVariablesAction` in a software project involves several stages from initial planning to final deployment and feedback collection. Below is a detailed roadmap for developing this feature, including key milestones and tasks. +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\RenameVariablesAction.kt +Developing a feature like the `RenameVariablesAction` in a software project involves several stages from initial planning to final deployment and feedback +collection. Below is a detailed roadmap for developing this feature, including key milestones and tasks. #### Phase 1: Planning and Design + 1. **Requirement Analysis** - - Gather requirements by consulting with stakeholders and potential users. - - Define the scope of the feature, including supported languages and IDEs. + +- Gather requirements by consulting with stakeholders and potential users. +- Define the scope of the feature, including supported languages and IDEs. 2. **Feasibility Study** - - Evaluate technical feasibility, including integration with existing systems like `ChatProxy` and the IntelliJ platform. - - Assess the availability of resources and tools needed for development. + +- Evaluate technical feasibility, including integration with existing systems like `ChatProxy` and the IntelliJ platform. +- Assess the availability of resources and tools needed for development. 3. **Design** - - Design the user interface and experience for selecting variables to rename. - - Outline the architecture of the feature, including how it interacts with the `ChatProxy` and processes suggestions. +- Design the user interface and experience for selecting variables to rename. +- Outline the architecture of the feature, including how it interacts with the `ChatProxy` and processes suggestions. #### Phase 2: Development + 4. **Setup Development Environment** - - Prepare the development environment, including necessary SDKs and plugins for IntelliJ platform development. + +- Prepare the development environment, including necessary SDKs and plugins for IntelliJ platform development. 5. **Implement Core Functionality** - - Develop the `RenameAPI` interface and its `SuggestionResponse` inner class to handle rename suggestions. - - Implement the `proxy` property to create a `ChatProxy` instance for accessing the rename API. + +- Develop the `RenameAPI` interface and its `SuggestionResponse` inner class to handle rename suggestions. +- Implement the `proxy` property to create a `ChatProxy` instance for accessing the rename API. 6. **User Interface Development** - - Implement the UI components for displaying rename suggestions and allowing users to select which variables to rename. + +- Implement the UI components for displaying rename suggestions and allowing users to select which variables to rename. 7. **Integration** - - Integrate the UI with the core functionality to fetch and display suggestions based on selected text. - - Ensure the feature can accurately replace selected variables with suggested names within the code. +- Integrate the UI with the core functionality to fetch and display suggestions based on selected text. +- Ensure the feature can accurately replace selected variables with suggested names within the code. #### Phase 3: Testing and Quality Assurance + 8. **Unit Testing** - - Write unit tests for individual components, including the API interaction, suggestion processing, and UI components. + +- Write unit tests for individual components, including the API interaction, suggestion processing, and UI components. 9. **Integration Testing** - - Test the feature as a whole to ensure it works seamlessly within the intended IDE environment and with various programming languages. + +- Test the feature as a whole to ensure it works seamlessly within the intended IDE environment and with various programming languages. 10. **User Acceptance Testing** - - Conduct user acceptance testing with a group of beta testers to gather feedback on usability and functionality. +- Conduct user acceptance testing with a group of beta testers to gather feedback on usability and functionality. #### Phase 4: Deployment + 11. **Deployment Preparation** - - Prepare the feature for deployment, including finalizing documentation and updating any necessary configurations. + +- Prepare the feature for deployment, including finalizing documentation and updating any necessary configurations. 12. **Release** - - Release the feature as part of a new version of the software or as an update to existing users. +- Release the feature as part of a new version of the software or as an update to existing users. #### Phase 5: Maintenance and Feedback + 13. **Collect Feedback** - - Collect user feedback through surveys, bug reports, and feature requests. + +- Collect user feedback through surveys, bug reports, and feature requests. 14. **Maintenance** - - Regularly update the feature to fix bugs, improve performance, and add enhancements based on user feedback. + +- Regularly update the feature to fix bugs, improve performance, and add enhancements based on user feedback. 15. **Iterate** - - Based on feedback and technological advancements, iterate on the feature to introduce new functionalities or improve existing ones. -This roadmap provides a structured approach to developing the `RenameVariablesAction` feature, ensuring thorough planning, development, testing, and deployment, followed by continuous improvement based on user feedback. +- Based on feedback and technological advancements, iterate on the feature to introduce new functionalities or improve existing ones. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\RecentCodeEditsAction.kt +This roadmap provides a structured approach to developing the `RenameVariablesAction` feature, ensuring thorough planning, development, testing, and deployment, +followed by continuous improvement based on user feedback. +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\code\RecentCodeEditsAction.kt #### Feature Development Roadmap for RecentCodeEditsAction -The `RecentCodeEditsAction` class is designed to enhance the user experience in an Integrated Development Environment (IDE) by providing quick access to a list of recent custom code edits. This roadmap outlines the planned features and improvements to make this tool more robust, user-friendly, and integrated with the development workflow. - +The `RecentCodeEditsAction` class is designed to enhance the user experience in an Integrated Development Environment (IDE) by providing quick access to a list +of recent custom code edits. This roadmap outlines the planned features and improvements to make this tool more robust, user-friendly, and integrated with the +development workflow. ##### Phase 1: Core Functionality Enhancement 1. **Improve Recent Edits Retrieval:** - - Optimize the retrieval of recent commands to ensure faster access and display. - - Implement caching mechanisms to reduce load times for frequently accessed commands. + +- Optimize the retrieval of recent commands to ensure faster access and display. +- Implement caching mechanisms to reduce load times for frequently accessed commands. 2. **Dynamic Update Mechanism:** - - Develop a dynamic update feature that refreshes the list of recent edits in real-time as new edits are made. + +- Develop a dynamic update feature that refreshes the list of recent edits in real-time as new edits are made. 3. **Custom Edit Action Enhancement:** - - Extend the `CustomEditAction` class to support more complex edit actions, including multi-file edits and refactorings. + +- Extend the `CustomEditAction` class to support more complex edit actions, including multi-file edits and refactorings. 4. **User Preferences:** - - Introduce settings allowing users to customize the number of recent edits displayed and the types of edits that should be tracked. +- Introduce settings allowing users to customize the number of recent edits displayed and the types of edits that should be tracked. ##### Phase 2: User Interface and Experience Improvements 1. **UI Enhancements:** - - Redesign the action presentation to make it more intuitive and visually appealing. - - Implement grouping or categorization of edits based on file type, project, or other criteria. + +- Redesign the action presentation to make it more intuitive and visually appealing. +- Implement grouping or categorization of edits based on file type, project, or other criteria. 2. **Search and Filter Capability:** - - Add a search bar to allow users to quickly find specific edits. - - Implement filtering options to help users narrow down the list based on criteria such as date, project, or file type. + +- Add a search bar to allow users to quickly find specific edits. +- Implement filtering options to help users narrow down the list based on criteria such as date, project, or file type. 3. **Keyboard Shortcuts:** - - Introduce customizable keyboard shortcuts for faster access to the recent edits list and individual edit actions. +- Introduce customizable keyboard shortcuts for faster access to the recent edits list and individual edit actions. ##### Phase 3: Integration and Collaboration Features 1. **Project-Specific Histories:** - - Enable project-specific tracking of recent edits to provide more relevant suggestions in multi-project environments. + +- Enable project-specific tracking of recent edits to provide more relevant suggestions in multi-project environments. 2. **Collaboration Tools Integration:** - - Integrate with version control systems (VCS) to highlight edits that have been shared or are new from collaborators. - - Implement a feature to share custom edits with team members directly from the IDE. + +- Integrate with version control systems (VCS) to highlight edits that have been shared or are new from collaborators. +- Implement a feature to share custom edits with team members directly from the IDE. 3. **Analytics and Insights:** - - Provide analytics on the user's editing patterns, suggesting optimizations and frequently used edits for quick access. +- Provide analytics on the user's editing patterns, suggesting optimizations and frequently used edits for quick access. ##### Phase 4: Advanced Features and Customization 1. **Macro Recording:** - - Allow users to record sequences of edits as macros that can be named, saved, and executed with a single action. + +- Allow users to record sequences of edits as macros that can be named, saved, and executed with a single action. 2. **AI-Assisted Code Edits:** - - Integrate AI-based suggestions for code edits based on the context and the user's past editing patterns. + +- Integrate AI-based suggestions for code edits based on the context and the user's past editing patterns. 3. **Plugin Ecosystem:** - - Develop an API that allows third-party plugins to add custom edit actions and integrations, enhancing the tool's capabilities. +- Develop an API that allows third-party plugins to add custom edit actions and integrations, enhancing the tool's capabilities. ##### Phase 5: Performance Optimization and Scalability 1. **Performance Tuning:** - - Conduct thorough performance testing and optimization to ensure the tool remains responsive even with large histories or complex edits. + +- Conduct thorough performance testing and optimization to ensure the tool remains responsive even with large histories or complex edits. 2. **Scalability Enhancements:** - - Implement scalable storage and retrieval mechanisms for edit histories to support enterprise-level usage and collaboration. +- Implement scalable storage and retrieval mechanisms for edit histories to support enterprise-level usage and collaboration. ##### Conclusion -The development roadmap for `RecentCodeEditsAction` aims to create a highly useful, customizable, and integrated tool that enhances the development workflow. By focusing on core functionality, user experience, collaboration, advanced features, and performance, this tool will become an indispensable part of the IDE ecosystem. +The development roadmap for `RecentCodeEditsAction` aims to create a highly useful, customizable, and integrated tool that enhances the development workflow. By +focusing on core functionality, user experience, collaboration, advanced features, and performance, this tool will become an indispensable part of the IDE +ecosystem. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\dev\AppServer.kt -Creating a feature development roadmap for the `AppServer` class within the context of a larger project involves outlining the current capabilities, identifying areas for improvement or expansion, and planning the development of new features in a structured manner. This roadmap will help guide the development process, ensuring that the project evolves in a way that meets user needs and leverages new technologies effectively. - +Creating a feature development roadmap for the `AppServer` class within the context of a larger project involves outlining the current capabilities, identifying +areas for improvement or expansion, and planning the development of new features in a structured manner. This roadmap will help guide the development process, +ensuring that the project evolves in a way that meets user needs and leverages new technologies effectively. #### Current Capabilities + - **Server Initialization**: Ability to initialize a Jetty server with a specified local name and port. - **Dynamic Context Handling**: Supports adding new web application contexts dynamically to the server. - **WebSocket Support**: Integration with JettyWebSocketServletContainerInitializer for WebSocket support. - **Chat Server Registry**: Maintains a registry of `ChatServer` instances, allowing for dynamic addition of chat applications. -- **Graceful Start/Stop**: Includes mechanisms for starting and stopping the server, with a dedicated thread to monitor server status and handle graceful shutdown. - +- **Graceful Start/Stop**: Includes mechanisms for starting and stopping the server, with a dedicated thread to monitor server status and handle graceful + shutdown. #### Short-Term Roadmap (0-6 Months) + 1. **Security Enhancements** - - Implement HTTPS support to ensure secure communication. - - Add basic authentication and authorization for accessing the server and its applications. + +- Implement HTTPS support to ensure secure communication. +- Add basic authentication and authorization for accessing the server and its applications. 2. **Performance Optimization** - - Analyze current performance bottlenecks and address them. - - Implement connection pooling for WebSocket connections to improve scalability. + +- Analyze current performance bottlenecks and address them. +- Implement connection pooling for WebSocket connections to improve scalability. 3. **Error Handling and Logging** - - Enhance error handling to provide more informative error messages to clients. - - Expand logging capabilities to include more detailed server and application-level events. + +- Enhance error handling to provide more informative error messages to clients. +- Expand logging capabilities to include more detailed server and application-level events. 4. **API Documentation** - - Create comprehensive API documentation to facilitate easier integration and usage by developers. + +- Create comprehensive API documentation to facilitate easier integration and usage by developers. 5. **Unit and Integration Testing** - - Develop a suite of unit and integration tests to ensure stability and reliability of the server and its applications. +- Develop a suite of unit and integration tests to ensure stability and reliability of the server and its applications. #### Mid-Term Roadmap (6-12 Months) + 1. **Plugin Architecture** - - Develop a plugin architecture to allow third-party developers to extend the server's functionality with custom handlers and services. + +- Develop a plugin architecture to allow third-party developers to extend the server's functionality with custom handlers and services. 2. **UI Improvements** - - Enhance the administrative UI for managing server settings, monitoring performance, and viewing logs. + +- Enhance the administrative UI for managing server settings, monitoring performance, and viewing logs. 3. **Database Integration** - - Integrate a database system for persistent storage of chat logs, user accounts, and application settings. + +- Integrate a database system for persistent storage of chat logs, user accounts, and application settings. 4. **Distributed Deployment** - - Enable the server to be deployed in a distributed environment, supporting load balancing and failover capabilities. +- Enable the server to be deployed in a distributed environment, supporting load balancing and failover capabilities. #### Long-Term Roadmap (1-2 Years) + 1. **Machine Learning Integration** - - Incorporate machine learning algorithms for chat moderation, user behavior analysis, and personalized user experiences. + +- Incorporate machine learning algorithms for chat moderation, user behavior analysis, and personalized user experiences. 2. **Internationalization and Localization** - - Support multiple languages in the server UI and chat applications to cater to a global audience. + +- Support multiple languages in the server UI and chat applications to cater to a global audience. 3. **Blockchain Integration** - - Explore the integration of blockchain technology for secure and verifiable transactions within chat applications. + +- Explore the integration of blockchain technology for secure and verifiable transactions within chat applications. 4. **IoT Integration** - - Develop capabilities for integrating with IoT devices, enabling new types of interactive applications. + +- Develop capabilities for integrating with IoT devices, enabling new types of interactive applications. 5. **Community and Ecosystem Development** - - Foster a developer community around the server platform, encouraging the sharing of plugins, applications, and best practices. + +- Foster a developer community around the server platform, encouraging the sharing of plugins, applications, and best practices. This roadmap is a living document and should be revisited and revised regularly based on user feedback, technological advancements, and strategic priorities. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\dev\InternalCoderAction.kt - #### Feature Development Roadmap for InternalCoderAction -The `InternalCoderAction` class is a part of a larger system designed to integrate coding assistance directly into the IntelliJ IDE, leveraging AI and web technologies. The roadmap below outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. - +The `InternalCoderAction` class is a part of a larger system designed to integrate coding assistance directly into the IntelliJ IDE, leveraging AI and web +technologies. The roadmap below outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. ##### Phase 1: Core Functionality and Stability 1. **Initial Setup and Integration** - - Ensure seamless integration with IntelliJ IDE. - - Verify the action is correctly triggered from the IDE with all necessary context. + +- Ensure seamless integration with IntelliJ IDE. +- Verify the action is correctly triggered from the IDE with all necessary context. 2. **Session Management** - - Improve session handling to ensure robustness, including error handling and session recovery. + +- Improve session handling to ensure robustness, including error handling and session recovery. 3. **UI and UX Enhancements** - - Develop a more intuitive and responsive UI for the coding agent within the IDE and the browser. - - Implement feedback mechanisms for users to report issues or suggest improvements directly from the UI. + +- Develop a more intuitive and responsive UI for the coding agent within the IDE and the browser. +- Implement feedback mechanisms for users to report issues or suggest improvements directly from the UI. 4. **Agent Communication** - - Enhance the efficiency and reliability of communication between the IDE, the server, and the coding agent. + +- Enhance the efficiency and reliability of communication between the IDE, the server, and the coding agent. 5. **Security Improvements** - - Implement comprehensive security measures to protect user data and code. - - Ensure all communications are encrypted and sessions are securely managed. +- Implement comprehensive security measures to protect user data and code. +- Ensure all communications are encrypted and sessions are securely managed. ##### Phase 2: Advanced Features and Integration 1. **AI-Powered Code Suggestions** - - Integrate advanced AI models to provide context-aware code suggestions and improvements. - - Allow users to customize the AI's behavior and response style. + +- Integrate advanced AI models to provide context-aware code suggestions and improvements. +- Allow users to customize the AI's behavior and response style. 2. **Collaborative Coding Sessions** - - Enable multiple users to join a coding session, allowing for real-time collaboration and code review. + +- Enable multiple users to join a coding session, allowing for real-time collaboration and code review. 3. **Cross-Platform Support** - - Ensure the coding agent and associated tools work seamlessly across different operating systems. - - Explore the possibility of supporting other IDEs or code editors. + +- Ensure the coding agent and associated tools work seamlessly across different operating systems. +- Explore the possibility of supporting other IDEs or code editors. 4. **Performance Optimization** - - Optimize the performance of the system to handle large projects and files without significant lag or resource consumption. + +- Optimize the performance of the system to handle large projects and files without significant lag or resource consumption. 5. **Extensibility** - - Develop a plugin system to allow third-party extensions and integrations. - - Encourage community contributions by making the project open-source. +- Develop a plugin system to allow third-party extensions and integrations. +- Encourage community contributions by making the project open-source. ##### Phase 3: Intelligence and Learning 1. **Contextual Learning** - - Implement machine learning algorithms that allow the coding agent to learn from the user's coding style and preferences. + +- Implement machine learning algorithms that allow the coding agent to learn from the user's coding style and preferences. 2. **Automated Code Refactoring** - - Introduce features for automated code refactoring based on best practices and user-defined rules. + +- Introduce features for automated code refactoring based on best practices and user-defined rules. 3. **Code Quality Analysis** - - Integrate code quality and security analysis tools directly into the coding session, providing real-time feedback and suggestions. + +- Integrate code quality and security analysis tools directly into the coding session, providing real-time feedback and suggestions. 4. **Personalized Learning and Assistance** - - Develop personalized learning paths for users to improve their coding skills, based on their interaction with the coding agent. + +- Develop personalized learning paths for users to improve their coding skills, based on their interaction with the coding agent. 5. **Advanced Debugging Assistance** - - Provide AI-powered debugging assistance, offering suggestions for fixing common errors and performance issues. +- Provide AI-powered debugging assistance, offering suggestions for fixing common errors and performance issues. ##### Phase 4: Community and Ecosystem 1. **Community Platform** - - Launch a community platform for users to share their experiences, code snippets, and custom extensions. + +- Launch a community platform for users to share their experiences, code snippets, and custom extensions. 2. **Marketplace for Extensions** - - Create a marketplace for third-party extensions, themes, and tools for the coding agent. + +- Create a marketplace for third-party extensions, themes, and tools for the coding agent. 3. **Educational Content and Tutorials** - - Collaborate with educators and content creators to provide tutorials, courses, and challenges that leverage the coding agent. + +- Collaborate with educators and content creators to provide tutorials, courses, and challenges that leverage the coding agent. 4. **Integration with Other Tools and Services** - - Develop integrations with version control systems, continuous integration tools, and cloud platforms. + +- Develop integrations with version control systems, continuous integration tools, and cloud platforms. 5. **Feedback Loop and Continuous Improvement** - - Establish a continuous feedback loop with the community to guide future development priorities and improvements. -This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The goal is to create a powerful, user-friendly coding assistant that enhances productivity and learning for developers of all skill levels. +- Establish a continuous feedback loop with the community to guide future development priorities and improvements. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\dev\PrintTreeAction.kt +This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The goal is to create a powerful, user-friendly +coding assistant that enhances productivity and learning for developers of all skill levels. -Creating a feature development roadmap for the `PrintTreeAction` class and its integration into an IntelliJ plugin involves planning out the stages of development, testing, and release. This roadmap will ensure that the feature is developed efficiently and meets the needs of its users. Here's a proposed roadmap: +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\dev\PrintTreeAction.kt +Creating a feature development roadmap for the `PrintTreeAction` class and its integration into an IntelliJ plugin involves planning out the stages of +development, testing, and release. This roadmap will ensure that the feature is developed efficiently and meets the needs of its users. Here's a proposed +roadmap: #### Phase 1: Planning and Design -- **Research and Requirements Gathering**: Understand the needs of developers who will use the `PrintTreeAction`. This might involve surveys, interviews, or studying similar features in other plugins. + +- **Research and Requirements Gathering**: Understand the needs of developers who will use the `PrintTreeAction`. This might involve surveys, interviews, or + studying similar features in other plugins. - **Feature Specification**: Clearly define what the `PrintTreeAction` will do, including any parameters or settings that can be configured by the user. - **Design**: Create a detailed design of the feature, including UI/UX design if applicable, and how it integrates with the existing plugin architecture. - #### Phase 2: Development + - **Environment Setup**: Ensure that all developers have the necessary tools and environments set up for IntelliJ plugin development. - **Implementation**: Start coding the feature based on the design documents. This includes: - Implementing the `PrintTreeAction` class. @@ -3849,227 +4746,300 @@ Creating a feature development roadmap for the `PrintTreeAction` class and its i - Adding a setting to enable/disable the feature (`devActions` setting). - **Code Review and Refinement**: Regularly review the code with peers to ensure it meets quality standards and adheres to the project's coding conventions. - #### Phase 3: Testing -- **Unit Testing**: Write and run unit tests to cover the new functionality. Ensure that the action behaves as expected in various scenarios. -- **Integration Testing**: Test the integration of the `PrintTreeAction` with the IntelliJ platform, verifying that it interacts correctly with other components. -- **User Acceptance Testing (UAT)**: Have a group of beta testers use the feature in their daily workflow to identify any usability issues or bugs that weren't caught during earlier testing phases. +- **Unit Testing**: Write and run unit tests to cover the new functionality. Ensure that the action behaves as expected in various scenarios. +- **Integration Testing**: Test the integration of the `PrintTreeAction` with the IntelliJ platform, verifying that it interacts correctly with other + components. +- **User Acceptance Testing (UAT)**: Have a group of beta testers use the feature in their daily workflow to identify any usability issues or bugs that weren't + caught during earlier testing phases. #### Phase 4: Documentation and Release + - **Documentation**: Write comprehensive documentation for the `PrintTreeAction`, including how to enable it, how to use it, and any configurable options. -- **Release Preparation**: Prepare the feature for release, which includes finalizing the documentation, updating the version number, and creating release notes. +- **Release Preparation**: Prepare the feature for release, which includes finalizing the documentation, updating the version number, and creating release + notes. - **Launch**: Release the updated plugin to the JetBrains Marketplace, making the `PrintTreeAction` available to all users. - #### Phase 5: Maintenance and Updates + - **Feedback Collection**: After the release, collect feedback from users about the feature. This can be done through surveys, issue trackers, or forums. - **Bug Fixing**: Address any bugs or issues reported by users in a timely manner. - **Feature Updates**: Based on user feedback, plan and implement updates to the `PrintTreeAction` to improve its functionality or add new features. -This roadmap is a guideline and may need adjustments based on the project's specific needs, user feedback, and any unforeseen challenges that arise during development. +This roadmap is a guideline and may need adjustments based on the project's specific needs, user feedback, and any unforeseen challenges that arise during +development. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\FileContextAction.kt -Creating a feature development roadmap for the `FileContextAction` class and its associated functionalities involves outlining a series of enhancements, new features, and optimizations that can be implemented to improve its utility, performance, and user experience. Below is a proposed roadmap that takes into consideration the current capabilities of the class as well as potential areas for growth. - +Creating a feature development roadmap for the `FileContextAction` class and its associated functionalities involves outlining a series of enhancements, new +features, and optimizations that can be implemented to improve its utility, performance, and user experience. Below is a proposed roadmap that takes into +consideration the current capabilities of the class as well as potential areas for growth. #### Phase 1: Core Functionality Enhancements -- **Refinement of File and Folder Support**: Enhance the logic that determines whether a file or folder is supported, making it more robust and flexible. This could involve adding more file types or allowing users to specify custom file types through settings. -- **Improved Configuration Handling**: Develop a more intuitive and flexible configuration system that allows users to easily modify the behavior of the `FileContextAction` class without needing to dive into the code. +- **Refinement of File and Folder Support**: Enhance the logic that determines whether a file or folder is supported, making it more robust and flexible. This + could involve adding more file types or allowing users to specify custom file types through settings. +- **Improved Configuration Handling**: Develop a more intuitive and flexible configuration system that allows users to easily modify the behavior of the + `FileContextAction` class without needing to dive into the code. #### Phase 2: User Experience Improvements -- **UI Feedback and Progress Indicators**: Implement UI feedback mechanisms such as progress bars or notifications to inform users about the status of actions being performed, especially for operations that might take a significant amount of time. -- **Error Handling and Reporting**: Enhance error handling to provide more informative and user-friendly error messages. Implement a system for logging and reporting errors that can help in troubleshooting and improving the software. +- **UI Feedback and Progress Indicators**: Implement UI feedback mechanisms such as progress bars or notifications to inform users about the status of actions + being performed, especially for operations that might take a significant amount of time. +- **Error Handling and Reporting**: Enhance error handling to provide more informative and user-friendly error messages. Implement a system for logging and + reporting errors that can help in troubleshooting and improving the software. #### Phase 3: Performance Optimization -- **Concurrency and Multithreading Enhancements**: Optimize the existing threading model to improve performance and responsiveness, especially for operations that can be parallelized. -- **Resource Management**: Implement better resource management strategies to ensure that the application remains responsive and stable, even when processing large numbers of files or very large files. +- **Concurrency and Multithreading Enhancements**: Optimize the existing threading model to improve performance and responsiveness, especially for operations + that can be parallelized. +- **Resource Management**: Implement better resource management strategies to ensure that the application remains responsive and stable, even when processing + large numbers of files or very large files. #### Phase 4: Integration and Extensibility -- **Plugin Ecosystem**: Develop an API or plugin system that allows third-party developers to extend the functionality of the `FileContextAction` class, such as adding support for new file types or integrating with other tools and services. -- **Version Control System Integration**: Integrate more closely with version control systems (e.g., Git) to provide context-aware features, such as automatically ignoring files that are listed in `.gitignore`. +- **Plugin Ecosystem**: Develop an API or plugin system that allows third-party developers to extend the functionality of the `FileContextAction` class, such as + adding support for new file types or integrating with other tools and services. +- **Version Control System Integration**: Integrate more closely with version control systems (e.g., Git) to provide context-aware features, such as + automatically ignoring files that are listed in `.gitignore`. #### Phase 5: Advanced Features -- **Machine Learning Assisted Refactoring**: Explore the integration of machine learning models to suggest or automatically perform code refactoring based on best practices or user-defined patterns. -- **Smart Context-Aware Actions**: Implement smart actions that can adapt based on the context of the selected file or folder, such as suggesting relevant templates or actions. +- **Machine Learning Assisted Refactoring**: Explore the integration of machine learning models to suggest or automatically perform code refactoring based on + best practices or user-defined patterns. +- **Smart Context-Aware Actions**: Implement smart actions that can adapt based on the context of the selected file or folder, such as suggesting relevant + templates or actions. #### Phase 6: Testing and Documentation -- **Comprehensive Testing Framework**: Develop a comprehensive testing framework that covers unit tests, integration tests, and UI tests to ensure the reliability and stability of the application. -- **Enhanced Documentation**: Create detailed documentation that covers all aspects of using and extending the `FileContextAction` class, including tutorials, API documentation, and best practices. +- **Comprehensive Testing Framework**: Develop a comprehensive testing framework that covers unit tests, integration tests, and UI tests to ensure the + reliability and stability of the application. +- **Enhanced Documentation**: Create detailed documentation that covers all aspects of using and extending the `FileContextAction` class, including tutorials, + API documentation, and best practices. #### Phase 7: Community and Collaboration -- **Community Engagement**: Establish a community forum or platform where users can share tips, ask questions, and contribute to the development of the `FileContextAction` class. -- **Collaboration Tools**: Implement tools or features that facilitate collaboration among team members directly within the IDE, such as shared configurations or collaborative editing. -This roadmap is designed to be iterative, allowing for adjustments and new ideas to be incorporated as the project evolves. Each phase builds upon the previous ones, gradually enhancing the `FileContextAction` class to become more powerful, user-friendly, and integrated into the developers' workflow. +- **Community Engagement**: Establish a community forum or platform where users can share tips, ask questions, and contribute to the development of the + `FileContextAction` class. +- **Collaboration Tools**: Implement tools or features that facilitate collaboration among team members directly within the IDE, such as shared configurations + or collaborative editing. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\AppendTextWithChatAction.kt +This roadmap is designed to be iterative, allowing for adjustments and new ideas to be incorporated as the project evolves. Each phase builds upon the previous +ones, gradually enhancing the `FileContextAction` class to become more powerful, user-friendly, and integrated into the developers' workflow. -The `AppendTextWithChatAction` class is a part of a larger project aimed at integrating AI capabilities into a development environment. This class specifically focuses on appending text to a user's selected text using an AI model. To further develop this feature and integrate more functionalities into the project, a feature development roadmap is proposed below. This roadmap outlines the progression from the current state to a more comprehensive and user-friendly AI integration. +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\AppendTextWithChatAction.kt +The `AppendTextWithChatAction` class is a part of a larger project aimed at integrating AI capabilities into a development environment. This class specifically +focuses on appending text to a user's selected text using an AI model. To further develop this feature and integrate more functionalities into the project, a +feature development roadmap is proposed below. This roadmap outlines the progression from the current state to a more comprehensive and user-friendly AI +integration. #### Phase 1: Core Functionality Enhancement -- **Improve AI Response Quality**: Research and implement advanced preprocessing and postprocessing techniques to enhance the relevance and quality of AI-generated text. -- **Custom AI Model Training**: Start a project to train custom AI models tailored to specific development contexts or languages, improving the accuracy and usefulness of appended text. -- **Performance Optimization**: Optimize the API call process and the handling of responses to reduce latency and improve the user experience. +- **Improve AI Response Quality**: Research and implement advanced preprocessing and postprocessing techniques to enhance the relevance and quality of + AI-generated text. +- **Custom AI Model Training**: Start a project to train custom AI models tailored to specific development contexts or languages, improving the accuracy and + usefulness of appended text. +- **Performance Optimization**: Optimize the API call process and the handling of responses to reduce latency and improve the user experience. #### Phase 2: User Experience Improvements -- **Configurable Settings UI**: Develop a user interface within the settings to allow users to customize AI parameters (e.g., temperature, model choice) according to their preferences. -- **Feedback Loop Integration**: Implement a feature for users to provide feedback on AI-generated text, which can be used for continuous improvement of the AI models. -- **Undo Functionality**: Introduce an undo action that allows users to revert changes made by the AI, enhancing the safety and usability of the feature. +- **Configurable Settings UI**: Develop a user interface within the settings to allow users to customize AI parameters (e.g., temperature, model choice) + according to their preferences. +- **Feedback Loop Integration**: Implement a feature for users to provide feedback on AI-generated text, which can be used for continuous improvement of the AI + models. +- **Undo Functionality**: Introduce an undo action that allows users to revert changes made by the AI, enhancing the safety and usability of the feature. #### Phase 3: Advanced Features -- **Contextual Awareness**: Enhance the AI's understanding of the broader context of the codebase, allowing for more accurate and contextually appropriate text generation. -- **Multi-Language Support**: Expand the feature to support multiple programming languages, making it versatile and useful for a broader range of developers. -- **Batch Processing Mode**: Implement a mode that allows users to apply the append action to multiple selections or files at once, improving efficiency for large-scale modifications. +- **Contextual Awareness**: Enhance the AI's understanding of the broader context of the codebase, allowing for more accurate and contextually appropriate text + generation. +- **Multi-Language Support**: Expand the feature to support multiple programming languages, making it versatile and useful for a broader range of developers. +- **Batch Processing Mode**: Implement a mode that allows users to apply the append action to multiple selections or files at once, improving efficiency for + large-scale modifications. #### Phase 4: Integration and Collaboration -- **Version Control System Integration**: Ensure that the feature works seamlessly with version control systems, allowing users to easily manage changes made by the AI. -- **Collaborative Editing Support**: Integrate the feature with collaborative coding environments, enabling real-time AI assistance during pair programming or team coding sessions. -- **API Expansion**: Open up the feature's API for third-party plugins and tools, allowing other developers to build on and extend the functionality. +- **Version Control System Integration**: Ensure that the feature works seamlessly with version control systems, allowing users to easily manage changes made by + the AI. +- **Collaborative Editing Support**: Integrate the feature with collaborative coding environments, enabling real-time AI assistance during pair programming or + team coding sessions. +- **API Expansion**: Open up the feature's API for third-party plugins and tools, allowing other developers to build on and extend the functionality. #### Phase 5: Analytics and Learning -- **Usage Analytics**: Collect anonymized data on how and when the feature is used to inform further development and improvement. -- **Adaptive Learning**: Implement machine learning algorithms that adapt the AI's behavior based on user interactions and preferences, personalizing the experience. -- **Community Sharing Platform**: Create a platform where users can share and discover custom configurations, models, or use cases, fostering a community around the tool. +- **Usage Analytics**: Collect anonymized data on how and when the feature is used to inform further development and improvement. +- **Adaptive Learning**: Implement machine learning algorithms that adapt the AI's behavior based on user interactions and preferences, personalizing the + experience. +- **Community Sharing Platform**: Create a platform where users can share and discover custom configurations, models, or use cases, fostering a community around + the tool. #### Phase 6: Security and Compliance + - **Security Enhancements**: Implement robust security measures to protect user data and code from unauthorized access or exposure. -- **Compliance Certifications**: Obtain necessary compliance certifications to ensure the tool meets industry standards and regulations, building trust with users. +- **Compliance Certifications**: Obtain necessary compliance certifications to ensure the tool meets industry standards and regulations, building trust with + users. -This roadmap is designed to be iterative, with each phase building upon the successes and lessons of the previous ones. Feedback from users and stakeholders will be crucial at every step to ensure that development aligns with user needs and expectations. +This roadmap is designed to be iterative, with each phase building upon the successes and lessons of the previous ones. Feedback from users and stakeholders +will be crucial at every step to ensure that development aligns with user needs and expectations. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\GenerateRelatedFileAction.kt -The code provided is part of a larger project aimed at integrating AI-driven functionalities into an IDE, specifically for generating analogue files based on directives. The roadmap for developing and enhancing this feature can be structured into several phases, each focusing on different aspects of functionality, user experience, and integration. Below is a proposed feature development roadmap: - +The code provided is part of a larger project aimed at integrating AI-driven functionalities into an IDE, specifically for generating analogue files based on +directives. The roadmap for developing and enhancing this feature can be structured into several phases, each focusing on different aspects of functionality, +user experience, and integration. Below is a proposed feature development roadmap: #### Phase 1: Core Functionality Development -- **1.1 Initial Setup and Configuration**: Establish the basic project structure, including necessary dependencies and initial configuration for interacting with the AI model. + +- **1.1 Initial Setup and Configuration**: Establish the basic project structure, including necessary dependencies and initial configuration for interacting + with the AI model. - **1.2 AI Integration**: Implement the core functionality to communicate with the AI model, sending directives and receiving generated code. - **1.3 File Generation**: Develop the mechanism to create new files based on the AI's output, ensuring correct path handling and file writing. - **1.4 Basic UI**: Create a simple user interface for inputting directives and triggering the file generation process. - #### Phase 2: Usability Enhancements + - **2.1 Advanced UI**: Enhance the user interface to improve usability, including better directive input methods, progress indication, and error handling. - **2.2 Directive Templates**: Introduce predefined directive templates for common tasks to simplify the user experience. - **2.3 Configuration Options**: Provide users with configuration options to customize the behavior of the AI model, such as setting the temperature parameter. - #### Phase 3: Integration and Compatibility + - **3.1 Project Context Awareness**: Enhance the tool to be more aware of the project context, allowing it to make more informed decisions and suggestions. - **3.2 Multi-Language Support**: Extend support to multiple programming languages, adapting the AI model's directives and output handling accordingly. - **3.3 Version Control Integration**: Implement features to better integrate with version control systems, such as automatic branching for generated files. - #### Phase 4: Advanced Features + - **4.1 Refactoring Assistance**: Develop functionalities to assist with code refactoring, using the AI to suggest improvements or alternatives. -- **4.2 Code Analysis and Suggestions**: Integrate code analysis tools to provide real-time feedback and suggestions based on the AI's understanding of best practices. +- **4.2 Code Analysis and Suggestions**: Integrate code analysis tools to provide real-time feedback and suggestions based on the AI's understanding of best + practices. - **4.3 Collaborative Features**: Implement collaborative features that allow teams to share directives and generated files, enhancing team productivity. - #### Phase 5: Optimization and Scaling -- **5.1 Performance Optimization**: Optimize the performance of the tool, ensuring it can handle large projects and complex directives efficiently. -- **5.2 Scalability Enhancements**: Make necessary architectural changes to ensure the tool can scale, both in terms of handling more users and integrating with larger and more complex AI models. -- **5.3 Cloud Integration**: Explore options for cloud integration, allowing for offloading computation-intensive tasks and enabling cloud-based storage for generated files. +- **5.1 Performance Optimization**: Optimize the performance of the tool, ensuring it can handle large projects and complex directives efficiently. +- **5.2 Scalability Enhancements**: Make necessary architectural changes to ensure the tool can scale, both in terms of handling more users and integrating with + larger and more complex AI models. +- **5.3 Cloud Integration**: Explore options for cloud integration, allowing for offloading computation-intensive tasks and enabling cloud-based storage for + generated files. #### Phase 6: Feedback Loop and Continuous Improvement -- **6.1 User Feedback Collection**: Implement mechanisms to collect user feedback directly through the tool, allowing for continuous improvement based on user needs. -- **6.2 Analytics and Usage Tracking**: Integrate analytics to understand how the tool is being used, identifying areas for improvement and new feature development. -- **6.3 Regular Updates and Maintenance**: Establish a regular update cycle, incorporating new AI model improvements, addressing bugs, and adding requested features. -This roadmap is designed to be iterative, with each phase building upon the previous ones. It allows for flexibility to adapt to new developments in AI technology, user feedback, and changing requirements. +- **6.1 User Feedback Collection**: Implement mechanisms to collect user feedback directly through the tool, allowing for continuous improvement based on user + needs. +- **6.2 Analytics and Usage Tracking**: Integrate analytics to understand how the tool is being used, identifying areas for improvement and new feature + development. +- **6.3 Regular Updates and Maintenance**: Establish a regular update cycle, incorporating new AI model improvements, addressing bugs, and adding requested + features. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\VoiceToTextAction.kt +This roadmap is designed to be iterative, with each phase building upon the previous ones. It allows for flexibility to adapt to new developments in AI +technology, user feedback, and changing requirements. -The `VoiceToTextAction` class provides a comprehensive framework for integrating dictation capabilities into an application, leveraging audio recording, processing, and speech-to-text conversion. To further enhance and expand its functionality, a feature development roadmap is proposed. This roadmap outlines a series of planned improvements and new features, aimed at increasing the utility, performance, and user experience of the dictation feature. +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\VoiceToTextAction.kt +The `VoiceToTextAction` class provides a comprehensive framework for integrating dictation capabilities into an application, leveraging audio recording, +processing, and speech-to-text conversion. To further enhance and expand its functionality, a feature development roadmap is proposed. This roadmap outlines a +series of planned improvements and new features, aimed at increasing the utility, performance, and user experience of the dictation feature. #### Phase 1: Core Improvements -1. **Enhanced Error Handling**: Improve error handling mechanisms to provide more informative feedback to users and developers, making it easier to diagnose and resolve issues. -2. **Performance Optimization**: Optimize the performance of audio processing and speech-to-text conversion to reduce latency and improve the responsiveness of the dictation feature. -3. **User Interface Enhancements**: Refine the user interface of the status dialog and other UI components to make them more intuitive and visually appealing. +1. **Enhanced Error Handling**: Improve error handling mechanisms to provide more informative feedback to users and developers, making it easier to diagnose and + resolve issues. +2. **Performance Optimization**: Optimize the performance of audio processing and speech-to-text conversion to reduce latency and improve the responsiveness of + the dictation feature. +3. **User Interface Enhancements**: Refine the user interface of the status dialog and other UI components to make them more intuitive and visually appealing. #### Phase 2: Feature Expansion + 1. **Language Support**: Introduce support for multiple languages, allowing users to dictate in their preferred language. -2. **Custom Vocabulary**: Implement a feature that allows users to add custom vocabulary words, improving the accuracy of speech-to-text conversion for domain-specific terms. +2. **Custom Vocabulary**: Implement a feature that allows users to add custom vocabulary words, improving the accuracy of speech-to-text conversion for + domain-specific terms. 3. **Noise Cancellation**: Develop and integrate advanced noise cancellation algorithms to enhance dictation accuracy in noisy environments. - #### Phase 3: Integration and Accessibility -1. **Plugin Ecosystem**: Develop a plugin system that allows third-party developers to extend and customize the dictation functionality, such as adding support for different speech-to-text APIs. -2. **Accessibility Features**: Introduce accessibility features, such as voice commands for controlling the dictation process, making the tool more accessible to users with disabilities. -3. **Mobile Compatibility**: Explore the possibility of extending the dictation feature to mobile platforms, either through a mobile app or a web-based solution that is mobile-friendly. +1. **Plugin Ecosystem**: Develop a plugin system that allows third-party developers to extend and customize the dictation functionality, such as adding support + for different speech-to-text APIs. +2. **Accessibility Features**: Introduce accessibility features, such as voice commands for controlling the dictation process, making the tool more accessible + to users with disabilities. +3. **Mobile Compatibility**: Explore the possibility of extending the dictation feature to mobile platforms, either through a mobile app or a web-based solution + that is mobile-friendly. #### Phase 4: Advanced Capabilities -1. **Real-time Feedback**: Implement real-time feedback mechanisms, such as live transcription previews, to give users immediate insight into the dictation process. -2. **Machine Learning Enhancements**: Leverage machine learning to continuously improve speech-to-text accuracy based on user corrections and feedback. -3. **Secure Data Processing**: Enhance data security measures to ensure that all audio recordings and transcriptions are processed and stored securely, respecting user privacy. +1. **Real-time Feedback**: Implement real-time feedback mechanisms, such as live transcription previews, to give users immediate insight into the dictation + process. +2. **Machine Learning Enhancements**: Leverage machine learning to continuously improve speech-to-text accuracy based on user corrections and feedback. +3. **Secure Data Processing**: Enhance data security measures to ensure that all audio recordings and transcriptions are processed and stored securely, + respecting user privacy. #### Phase 5: Community and Support + 1. **Documentation and Tutorials**: Create comprehensive documentation and tutorials to help users and developers get the most out of the dictation feature. 2. **Community Forum**: Establish a community forum for users and developers to share tips, ask questions, and provide feedback on the dictation feature. -3. **Professional Support**: Offer professional support services for businesses and organizations that require assistance with integrating and customizing the dictation feature. +3. **Professional Support**: Offer professional support services for businesses and organizations that require assistance with integrating and customizing the + dictation feature. -This roadmap is designed to be iterative, with each phase building upon the successes and lessons learned from the previous ones. Feedback from users and developers will be crucial in shaping the direction and priorities of future development efforts. +This roadmap is designed to be iterative, with each phase building upon the successes and lessons learned from the previous ones. Feedback from users and +developers will be crucial in shaping the direction and priorities of future development efforts. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\CodeChatAction.kt -Creating a feature development roadmap for the `CodeChatAction` class involves outlining the planned enhancements, improvements, and new functionalities that will be added over time. This roadmap will help guide the development process, prioritize tasks, and communicate the project's direction to stakeholders. Here's a proposed roadmap based on the existing codebase: - +Creating a feature development roadmap for the `CodeChatAction` class involves outlining the planned enhancements, improvements, and new functionalities that +will be added over time. This roadmap will help guide the development process, prioritize tasks, and communicate the project's direction to stakeholders. Here's +a proposed roadmap based on the existing codebase: #### Phase 1: Core Functionality Enhancements -- **Improved Language Support**: Expand the `ComputerLanguage` class to support more programming languages, enhancing the utility of the code chat for a broader range of developers. -- **Session Management**: Implement advanced session management features to handle multiple concurrent code chat sessions more efficiently, including session expiration and cleanup mechanisms. -- **User Authentication**: Integrate user authentication to ensure that only authorized users can initiate code chat sessions, enhancing security and privacy. +- **Improved Language Support**: Expand the `ComputerLanguage` class to support more programming languages, enhancing the utility of the code chat for a broader + range of developers. +- **Session Management**: Implement advanced session management features to handle multiple concurrent code chat sessions more efficiently, including session + expiration and cleanup mechanisms. +- **User Authentication**: Integrate user authentication to ensure that only authorized users can initiate code chat sessions, enhancing security and privacy. #### Phase 2: User Interface and Experience -- **Customizable UI Themes**: Develop customizable UI themes for the code chat interface, allowing users to personalize their experience according to their preferences. -- **Real-Time Collaboration**: Introduce real-time code editing and chat functionalities, enabling multiple users to collaborate on the same piece of code simultaneously. -- **Code Snippet Sharing**: Implement a feature for sharing code snippets directly within the chat interface, facilitating easier communication and collaboration. +- **Customizable UI Themes**: Develop customizable UI themes for the code chat interface, allowing users to personalize their experience according to their + preferences. +- **Real-Time Collaboration**: Introduce real-time code editing and chat functionalities, enabling multiple users to collaborate on the same piece of code + simultaneously. +- **Code Snippet Sharing**: Implement a feature for sharing code snippets directly within the chat interface, facilitating easier communication and + collaboration. #### Phase 3: Integration and Compatibility -- **IDE Integration**: Extend compatibility to other popular Integrated Development Environments (IDEs) beyond IntelliJ, such as Visual Studio Code and Eclipse, to reach a wider audience. -- **Mobile Support**: Develop a mobile-friendly version of the code chat interface, allowing users to participate in code discussions on-the-go. -- **API Exposures**: Create a public API for the code chat functionality, enabling third-party developers to integrate code chat features into their own applications or services. +- **IDE Integration**: Extend compatibility to other popular Integrated Development Environments (IDEs) beyond IntelliJ, such as Visual Studio Code and Eclipse, + to reach a wider audience. +- **Mobile Support**: Develop a mobile-friendly version of the code chat interface, allowing users to participate in code discussions on-the-go. +- **API Exposures**: Create a public API for the code chat functionality, enabling third-party developers to integrate code chat features into their own + applications or services. #### Phase 4: Advanced Features and Analytics -- **AI-Powered Code Suggestions**: Integrate AI-powered code suggestion features that analyze the ongoing discussion and provide relevant code examples, documentation, and tips. -- **Usage Analytics**: Implement analytics to track usage patterns, popular features, and user feedback, guiding future development priorities based on data-driven insights. -- **Custom Plugins**: Support for custom plugins that allow users to extend the functionality of the code chat with their own or third-party developed features. +- **AI-Powered Code Suggestions**: Integrate AI-powered code suggestion features that analyze the ongoing discussion and provide relevant code examples, + documentation, and tips. +- **Usage Analytics**: Implement analytics to track usage patterns, popular features, and user feedback, guiding future development priorities based on + data-driven insights. +- **Custom Plugins**: Support for custom plugins that allow users to extend the functionality of the code chat with their own or third-party developed features. #### Phase 5: Community and Support + - **Community Forum**: Establish a community forum for users to share tips, ask questions, and provide feedback on the code chat tool. -- **Comprehensive Documentation**: Develop comprehensive documentation covering all features, setup instructions, and best practices for using the code chat tool effectively. -- **Professional Support**: Offer professional support services for enterprise users, including custom development, priority bug fixes, and dedicated support channels. +- **Comprehensive Documentation**: Develop comprehensive documentation covering all features, setup instructions, and best practices for using the code chat + tool effectively. +- **Professional Support**: Offer professional support services for enterprise users, including custom development, priority bug fixes, and dedicated support + channels. -This roadmap is a living document and should be revisited and revised regularly based on user feedback, technological advancements, and changing priorities within the development team. +This roadmap is a living document and should be revisited and revised regularly based on user feedback, technological advancements, and changing priorities +within the development team. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\compiled_documentation.md -Creating a feature development roadmap involves outlining the stages of development for new features or enhancements within a project. This roadmap serves as a strategic document that guides the development team through the planning, execution, and release phases of the feature development process. Below is a generic roadmap template for developing new features, which can be adapted to fit specific projects or organizational needs. - +Creating a feature development roadmap involves outlining the stages of development for new features or enhancements within a project. This roadmap serves as a +strategic document that guides the development team through the planning, execution, and release phases of the feature development process. Below is a generic +roadmap template for developing new features, which can be adapted to fit specific projects or organizational needs. #### Phase 1: Ideation and Conceptualization @@ -4077,21 +5047,21 @@ Creating a feature development roadmap involves outlining the stages of developm 2. **Feasibility Study**: Evaluate the technical feasibility, potential market impact, and alignment with business goals for each idea. 3. **Concept Approval**: Present the most promising ideas to stakeholders for approval and prioritization. - #### Phase 2: Planning and Design 1. **Requirement Gathering**: Define detailed functional and non-functional requirements through discussions with stakeholders. -2. **Design and Prototyping**: Create initial design mockups or prototypes to visualize the feature. This may include UI/UX designs, system architecture, and data models. +2. **Design and Prototyping**: Create initial design mockups or prototypes to visualize the feature. This may include UI/UX designs, system architecture, and + data models. 3. **Technical Specification**: Document the technical specifications, including technology stack, integration points, and data flows. 4. **Roadmap Creation**: Develop a detailed feature development roadmap, outlining key milestones, timelines, and resource allocations. - #### Phase 3: Development and Implementation 1. **Development Setup**: Set up the development environment, including code repositories, development tools, and branching strategies. -2. **Coding and Development**: Start the coding process based on the technical specifications. This phase includes implementing core functionalities, UI elements, and integrations. -3. **Code Review and Quality Assurance**: Conduct regular code reviews and quality assurance (QA) testing to ensure code quality and adherence to specifications. - +2. **Coding and Development**: Start the coding process based on the technical specifications. This phase includes implementing core functionalities, UI + elements, and integrations. +3. **Code Review and Quality Assurance**: Conduct regular code reviews and quality assurance (QA) testing to ensure code quality and adherence to + specifications. #### Phase 4: Testing and Validation @@ -4100,7 +5070,6 @@ Creating a feature development roadmap involves outlining the stages of developm 3. **User Acceptance Testing (UAT)**: Conduct UAT with a select group of end-users to validate the feature against user requirements and gather feedback. 4. **Bug Fixing**: Address any issues or bugs identified during the testing phase. - #### Phase 5: Deployment and Release 1. **Deployment Planning**: Plan the deployment process, including scheduling, deployment strategies (e.g., blue-green, canary), and rollback plans. @@ -4108,141 +5077,179 @@ Creating a feature development roadmap involves outlining the stages of developm 3. **Feature Launch**: Deploy the feature to production and announce the launch to users. 4. **Post-launch Monitoring**: Monitor the feature for any issues and gather user feedback for future improvements. - #### Phase 6: Evaluation and Iteration 1. **Performance Analysis**: Analyze usage data and performance metrics to assess the impact of the feature. 2. **Feedback Collection**: Collect and review user feedback to identify areas for improvement. 3. **Iterative Development**: Plan and implement iterative improvements based on the evaluation and feedback. -By following this roadmap, development teams can systematically approach feature development, ensuring that each stage is carefully planned and executed to deliver high-quality features that meet user needs and business objectives. +By following this roadmap, development teams can systematically approach feature development, ensuring that each stage is carefully planned and executed to +deliver high-quality features that meet user needs and business objectives. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\CreateFileFromDescriptionAction.kt -The code snippet provided is part of a larger project aimed at integrating natural language processing (NLP) capabilities into a development environment, specifically for generating files based on natural language directives. The `CreateFileFromDescriptionAction` class is a key component of this system, leveraging an AI model to interpret directives and generate corresponding files within a project structure. To further develop and enhance this system, a feature development roadmap is proposed below, outlining potential improvements and expansions in a phased approach. - +The code snippet provided is part of a larger project aimed at integrating natural language processing (NLP) capabilities into a development environment, +specifically for generating files based on natural language directives. The `CreateFileFromDescriptionAction` class is a key component of this system, +leveraging an AI model to interpret directives and generate corresponding files within a project structure. To further develop and enhance this system, a +feature development roadmap is proposed below, outlining potential improvements and expansions in a phased approach. #### Phase 1: Core Functionality Enhancements -- **Improved File Generation Logic**: Refine the AI's understanding of directives to generate more accurate and contextually appropriate files. This could involve training the model on a larger dataset or incorporating more sophisticated NLP techniques. -- **Directive Language Expansion**: Expand the system's ability to understand directives in multiple languages, making the tool more accessible to a global user base. -- **Feedback Loop Integration**: Implement a mechanism for users to provide feedback on the generated files, which can be used to further train and refine the AI model. +- **Improved File Generation Logic**: Refine the AI's understanding of directives to generate more accurate and contextually appropriate files. This could + involve training the model on a larger dataset or incorporating more sophisticated NLP techniques. +- **Directive Language Expansion**: Expand the system's ability to understand directives in multiple languages, making the tool more accessible to a global user + base. +- **Feedback Loop Integration**: Implement a mechanism for users to provide feedback on the generated files, which can be used to further train and refine the + AI model. #### Phase 2: User Experience Improvements -- **Interactive Directive Interface**: Develop a more interactive interface for inputting directives, possibly including suggestions, autocomplete, and real-time previews of potential outputs. -- **Enhanced Error Handling and Reporting**: Improve the system's ability to handle errors gracefully, providing users with clear, actionable information when something goes wrong. -- **Customization Options**: Allow users to customize various aspects of the file generation process, such as specifying naming conventions, default file headers, or preferred coding styles. +- **Interactive Directive Interface**: Develop a more interactive interface for inputting directives, possibly including suggestions, autocomplete, and + real-time previews of potential outputs. +- **Enhanced Error Handling and Reporting**: Improve the system's ability to handle errors gracefully, providing users with clear, actionable information when + something goes wrong. +- **Customization Options**: Allow users to customize various aspects of the file generation process, such as specifying naming conventions, default file + headers, or preferred coding styles. #### Phase 3: Integration and Expansion -- **IDE Integration**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ, Eclipse, and Visual Studio Code, allowing users to use this functionality directly within their preferred development environment. -- **Support for Additional File Types**: Extend the system to support a wider range of file types and languages, catering to a broader spectrum of development projects. -- **Collaboration Features**: Introduce features that support team collaboration, such as shared directive libraries, project-specific configurations, and integration with version control systems. +- **IDE Integration**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ, Eclipse, and Visual Studio Code, allowing users to + use this functionality directly within their preferred development environment. +- **Support for Additional File Types**: Extend the system to support a wider range of file types and languages, catering to a broader spectrum of development + projects. +- **Collaboration Features**: Introduce features that support team collaboration, such as shared directive libraries, project-specific configurations, and + integration with version control systems. #### Phase 4: Advanced Features and AI Capabilities -- **Context-Aware File Generation**: Enhance the AI model to consider the broader context of the project when generating files, potentially suggesting new files or modifications based on the project's current state and history. -- **Automated Code Refactoring Suggestions**: Implement functionality for the AI to suggest code refactoring opportunities based on best practices and the latest coding standards. -- **Natural Language Code Queries**: Develop the ability for users to query their codebase using natural language, enabling them to find functions, classes, and files or understand code functionality without digging through the code manually. +- **Context-Aware File Generation**: Enhance the AI model to consider the broader context of the project when generating files, potentially suggesting new files + or modifications based on the project's current state and history. +- **Automated Code Refactoring Suggestions**: Implement functionality for the AI to suggest code refactoring opportunities based on best practices and the + latest coding standards. +- **Natural Language Code Queries**: Develop the ability for users to query their codebase using natural language, enabling them to find functions, classes, and + files or understand code functionality without digging through the code manually. #### Phase 5: Scalability and Performance Optimization + - **Performance Optimization**: Optimize the system for performance, ensuring it can handle large projects and complex directives efficiently. -- **Scalability Enhancements**: Ensure the system can scale to support a large number of concurrent users and projects, including the potential for cloud-based processing and storage. +- **Scalability Enhancements**: Ensure the system can scale to support a large number of concurrent users and projects, including the potential for cloud-based + processing and storage. -This roadmap outlines a comprehensive plan for developing a robust system that leverages AI to interpret natural language directives for file generation within software projects. Each phase builds upon the last, gradually introducing more sophisticated features and capabilities to enhance the user experience, improve integration, and expand the system's applicability and utility. +This roadmap outlines a comprehensive plan for developing a robust system that leverages AI to interpret natural language directives for file generation within +software projects. Each phase builds upon the last, gradually introducing more sophisticated features and capabilities to enhance the user experience, improve +integration, and expand the system's applicability and utility. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\DiffChatAction.kt -The `DiffChatAction` class is a sophisticated component designed to enhance the developer experience within an IDE, specifically focusing on facilitating code reviews and discussions through a chat interface that supports diff patches. This roadmap outlines the planned features and improvements to further develop this component, ensuring it becomes an indispensable tool for developers. - +The `DiffChatAction` class is a sophisticated component designed to enhance the developer experience within an IDE, specifically focusing on facilitating code +reviews and discussions through a chat interface that supports diff patches. This roadmap outlines the planned features and improvements to further develop this +component, ensuring it becomes an indispensable tool for developers. #### Phase 1: Core Functionality Enhancement + - **Refinement of Diff Rendering**: Improve the rendering of diff patches within the chat interface to make them more readable and visually appealing. -- **Selection Context Expansion**: Automatically include more context around selected text before initiating the chat, helping reviewers understand the changes better. +- **Selection Context Expansion**: Automatically include more context around selected text before initiating the chat, helping reviewers understand the changes + better. - **Performance Optimization**: Optimize the processing and rendering of diffs to ensure the tool remains responsive, even with large diffs or high chat volume. - #### Phase 2: User Experience Improvements -- **User Interface Polish**: Enhance the chat interface with a more intuitive design, including better organization of chat threads and clearer indication of code blocks. + +- **User Interface Polish**: Enhance the chat interface with a more intuitive design, including better organization of chat threads and clearer indication of + code blocks. - **Diff Application Confirmation**: Implement a confirmation dialog before applying diffs to the codebase, preventing accidental modifications. - **Customizable Diff Context**: Allow users to customize the amount of context shown around diffs, catering to personal preferences or project requirements. - #### Phase 3: Collaboration Features -- **Real-Time Collaboration**: Enable real-time updates in the chat for simultaneous code reviews, allowing multiple developers to discuss and apply diffs synchronously. -- **Threaded Conversations**: Introduce threaded conversations within the chat, making it easier to follow and participate in multiple discussions about different code blocks. -- **Annotations and Comments**: Allow users to add annotations and comments directly on the diffs, facilitating more detailed feedback and discussions. +- **Real-Time Collaboration**: Enable real-time updates in the chat for simultaneous code reviews, allowing multiple developers to discuss and apply diffs + synchronously. +- **Threaded Conversations**: Introduce threaded conversations within the chat, making it easier to follow and participate in multiple discussions about + different code blocks. +- **Annotations and Comments**: Allow users to add annotations and comments directly on the diffs, facilitating more detailed feedback and discussions. #### Phase 4: Integration and Compatibility + - **Cross-Platform Support**: Ensure the tool is compatible with different operating systems and IDEs, broadening its user base. -- **Version Control Integration**: Integrate directly with version control systems (e.g., Git) to fetch diffs from pull requests and push applied diffs as commits. +- **Version Control Integration**: Integrate directly with version control systems (e.g., Git) to fetch diffs from pull requests and push applied diffs as + commits. - **Language Support Expansion**: Extend support to more programming languages, making the tool useful for a wider range of development projects. - #### Phase 5: Advanced Features + - **AI-Assisted Code Review**: Incorporate AI to suggest improvements or identify potential issues within the diffs, enhancing the quality of code reviews. - **Customizable Workflows**: Allow teams to customize the review workflow, including automated checks or approvals before diffs can be applied. -- **Analytics and Reporting**: Provide analytics on code review activities, such as frequency, participation rates, and common issues identified, helping teams improve their review processes. - +- **Analytics and Reporting**: Provide analytics on code review activities, such as frequency, participation rates, and common issues identified, helping teams + improve their review processes. #### Phase 6: Security and Compliance -- **Security Enhancements**: Implement robust security measures to protect the code and discussions from unauthorized access. -- **Compliance Features**: Add features to help teams comply with coding standards and regulatory requirements, such as automatic code formatting or compliance checks. +- **Security Enhancements**: Implement robust security measures to protect the code and discussions from unauthorized access. +- **Compliance Features**: Add features to help teams comply with coding standards and regulatory requirements, such as automatic code formatting or compliance + checks. #### Conclusion -The development roadmap for the `DiffChatAction` class aims to transform it into a comprehensive tool that not only facilitates efficient code reviews and discussions but also integrates seamlessly into the developer's workflow, supports collaboration, and ensures high standards of code quality and security. By progressively implementing these features, the tool will become an essential component of the development ecosystem. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\ReplaceWithSuggestionsAction.kt +The development roadmap for the `DiffChatAction` class aims to transform it into a comprehensive tool that not only facilitates efficient code reviews and +discussions but also integrates seamlessly into the developer's workflow, supports collaboration, and ensures high standards of code quality and security. By +progressively implementing these features, the tool will become an essential component of the development ecosystem. -The code snippet provided outlines a class `ReplaceWithSuggestionsAction` that extends `SelectionAction` and is designed to interact with a virtual API to suggest text replacements within a selected text in an IDE environment. This functionality is particularly useful for code editors and IDE plugins that aim to enhance developer productivity by automating code suggestions and replacements. Below is a feature development roadmap to further develop and enhance this functionality. +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\ReplaceWithSuggestionsAction.kt +The code snippet provided outlines a class `ReplaceWithSuggestionsAction` that extends `SelectionAction` and is designed to interact with a virtual API +to suggest text replacements within a selected text in an IDE environment. This functionality is particularly useful for code editors and IDE plugins that aim +to enhance developer productivity by automating code suggestions and replacements. Below is a feature development roadmap to further develop and enhance this +functionality. #### Phase 1: Core Functionality Enhancement + - **Improve Text Suggestion Algorithm**: Enhance the virtual API's text suggestion algorithm to provide more accurate and contextually relevant suggestions. - **Support Multiple Languages**: Extend the functionality to support multiple programming languages, making the tool more versatile. - **User Preferences Learning**: Implement machine learning to adapt suggestions based on the user's coding style and preferences over time. - #### Phase 2: User Interface Improvements + - **Customizable UI**: Allow users to customize the UI of the suggestion dialog, including themes and layout. - **Preview Functionality**: Enable a preview feature that shows how the code would change with the selected suggestion before applying it. - **Integration with Documentation**: Provide an option to view documentation or examples related to the suggested text directly within the dialog. - #### Phase 3: Performance and Scalability + - **Asynchronous Processing**: Optimize the suggestion process to run asynchronously, ensuring that the IDE remains responsive. - **Caching Mechanism**: Implement a caching mechanism for suggestions to reduce API calls and improve performance. - **Scalable Architecture**: Refactor the backend to support a scalable architecture, allowing for efficient handling of a large number of requests. - #### Phase 4: Collaboration and Sharing + - **Team Customization**: Allow teams to customize suggestions based on their codebase and coding standards. - **Sharing Suggestions**: Implement functionality for users to share their custom suggestions or templates with their team or the community. -- **Integration with Version Control Systems**: Provide seamless integration with version control systems to suggest text replacements based on the project's history and contributors' styles. - +- **Integration with Version Control Systems**: Provide seamless integration with version control systems to suggest text replacements based on the project's + history and contributors' styles. #### Phase 5: Advanced Features and Integrations + - **AI-Powered Refactoring**: Integrate advanced AI models to suggest not just text replacements but also code refactoring opportunities. - **Plugin Ecosystem**: Develop a plugin ecosystem allowing third-party developers to extend and add new functionalities. - **Cross-Platform Support**: Ensure the tool is compatible with various IDEs and editors, providing a consistent experience across platforms. - #### Phase 6: Feedback Loop and Continuous Improvement + - **User Feedback System**: Implement a system for collecting user feedback on suggestions to continuously improve the suggestion algorithm. -- **Analytics and Reporting**: Provide analytics and reporting tools for users to understand their usage patterns and the impact of suggestions on their productivity. -- **Regular Updates and Maintenance**: Establish a schedule for regular updates and maintenance to keep the tool up-to-date with the latest technologies and user needs. +- **Analytics and Reporting**: Provide analytics and reporting tools for users to understand their usage patterns and the impact of suggestions on their + productivity. +- **Regular Updates and Maintenance**: Establish a schedule for regular updates and maintenance to keep the tool up-to-date with the latest technologies and + user needs. -This roadmap outlines a comprehensive approach to developing a sophisticated code suggestion and replacement tool that evolves with user needs and technological advancements. +This roadmap outlines a comprehensive approach to developing a sophisticated code suggestion and replacement tool that evolves with user needs and technological +advancements. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\RedoLast.kt -Developing a feature, especially for a software project like an IntelliJ plugin, requires careful planning and execution. Below is a feature development roadmap for enhancing the "RedoLast" action, which allows users to redo the last AI Coder action they performed in the editor. This roadmap outlines the phases from initial planning to release and maintenance. - +Developing a feature, especially for a software project like an IntelliJ plugin, requires careful planning and execution. Below is a feature development roadmap +for enhancing the "RedoLast" action, which allows users to redo the last AI Coder action they performed in the editor. This roadmap outlines the phases from +initial planning to release and maintenance. #### Phase 1: Research and Planning + - **Duration:** 2 weeks - **Goals:** - Gather feedback from current users about the existing "RedoLast" feature. @@ -4250,8 +5257,8 @@ Developing a feature, especially for a software project like an IntelliJ plugin, - Research how similar plugins implement redo functionalities. - Define clear objectives for the feature enhancement based on research findings. - #### Phase 2: Design + - **Duration:** 3 weeks - **Goals:** - Design a more intuitive UI/UX for the "RedoLast" action, ensuring it's easily accessible and understandable. @@ -4259,8 +5266,8 @@ Developing a feature, especially for a software project like an IntelliJ plugin, - Plan for backward compatibility with older versions of the plugin. - Conduct a design review with stakeholders and incorporate feedback. - #### Phase 3: Development + - **Duration:** 6 weeks - **Goals:** - Implement the redesigned "RedoLast" feature based on the design documents. @@ -4268,8 +5275,8 @@ Developing a feature, especially for a software project like an IntelliJ plugin, - Develop unit tests and integration tests to cover new code paths and scenarios. - Perform code reviews and refactorings as necessary to maintain code quality. - #### Phase 4: Testing & Quality Assurance + - **Duration:** 4 weeks - **Goals:** - Conduct thorough testing, including manual and automated tests, to ensure the feature works as expected across different environments. @@ -4277,394 +5284,473 @@ Developing a feature, especially for a software project like an IntelliJ plugin, - Validate the feature against the initial objectives and user requirements. - Collect and incorporate feedback from beta testers. - #### Phase 5: Documentation & Training + - **Duration:** 2 weeks - **Goals:** - Update the plugin documentation to include information about the new "RedoLast" feature enhancements. - Create tutorial videos or guides to help users understand how to use the new functionality. - Train support staff on the new feature to ensure they can assist users effectively. - #### Phase 6: Release + - **Duration:** 1 week - **Goals:** - Prepare and execute a launch plan for the new feature, including marketing communications if applicable. - Release the feature as part of a new version of the plugin. - Monitor the release for any immediate issues or feedback. - #### Phase 7: Maintenance & Iteration + - **Duration:** Ongoing - **Goals:** - Collect and analyze user feedback on the new feature. - Identify any bugs or performance issues reported by users and address them in subsequent updates. - Plan for future enhancements based on user feedback and technological advancements. -This roadmap is a guideline and may be adjusted based on project needs, unexpected challenges, or new opportunities that arise during development. Regular status meetings and updates will ensure the project stays on track and stakeholders are informed of progress. +This roadmap is a guideline and may be adjusted based on project needs, unexpected challenges, or new opportunities that arise during development. Regular +status meetings and updates will ensure the project stays on track and stakeholders are informed of progress. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\generic\GenerateDocumentationAction.kt - #### Feature Development Roadmap for GenerateDocumentationAction -The `GenerateDocumentationAction` class is designed to automate the process of compiling documentation from code files within a project. This roadmap outlines the planned features and improvements to enhance its functionality, usability, and integration capabilities. - +The `GenerateDocumentationAction` class is designed to automate the process of compiling documentation from code files within a project. This roadmap outlines +the planned features and improvements to enhance its functionality, usability, and integration capabilities. ##### Phase 1: Core Functionality Enhancements 1. **Improved Content Transformation** - - Implement advanced parsing and transformation logic to handle a wider range of programming languages and documentation styles. - - Integrate machine learning models for better understanding and summarization of code. + +- Implement advanced parsing and transformation logic to handle a wider range of programming languages and documentation styles. +- Integrate machine learning models for better understanding and summarization of code. 2. **User Interface Improvements** - - Enhance the settings UI to include more customization options such as selecting specific file types or directories for documentation compilation. - - Provide real-time previews of the generated documentation. + +- Enhance the settings UI to include more customization options such as selecting specific file types or directories for documentation compilation. +- Provide real-time previews of the generated documentation. 3. **Performance Optimization** - - Optimize the file processing and content transformation pipeline for faster execution. - - Implement asynchronous processing to prevent UI freezing during documentation compilation. +- Optimize the file processing and content transformation pipeline for faster execution. +- Implement asynchronous processing to prevent UI freezing during documentation compilation. ##### Phase 2: Integration and Compatibility 1. **Version Control System Integration** - - Add support for automatically fetching and updating documentation based on version control system events (e.g., post-commit hooks). - - Implement functionality to push generated documentation to specified branches or repositories. + +- Add support for automatically fetching and updating documentation based on version control system events (e.g., post-commit hooks). +- Implement functionality to push generated documentation to specified branches or repositories. 2. **Support for Additional IDEs** - - Extend compatibility to other popular IDEs beyond IntelliJ, such as VS Code and Eclipse. - - Ensure seamless integration with the build tools and plugins commonly used in these environments. + +- Extend compatibility to other popular IDEs beyond IntelliJ, such as VS Code and Eclipse. +- Ensure seamless integration with the build tools and plugins commonly used in these environments. 3. **Customizable Templates** - - Allow users to define custom templates for the generated documentation to match their project's style guidelines or preferences. - - Support for importing and exporting templates for easy sharing within teams. +- Allow users to define custom templates for the generated documentation to match their project's style guidelines or preferences. +- Support for importing and exporting templates for easy sharing within teams. ##### Phase 3: Advanced Features and Collaboration Tools 1. **Collaborative Editing** - - Integrate real-time collaborative editing features for teams to work on documentation together. - - Implement versioning and change tracking for documentation files. + +- Integrate real-time collaborative editing features for teams to work on documentation together. +- Implement versioning and change tracking for documentation files. 2. **Automated Documentation Review** - - Develop a feature for automated suggestions on improving documentation quality, such as identifying unclear descriptions or missing information. - - Integrate with code review tools to include documentation quality as part of the code review process. + +- Develop a feature for automated suggestions on improving documentation quality, such as identifying unclear descriptions or missing information. +- Integrate with code review tools to include documentation quality as part of the code review process. 3. **Documentation Analytics** - - Provide analytics on documentation usage, such as frequently accessed sections or outdated pages. - - Implement feedback mechanisms for readers to suggest improvements or report issues with the documentation. +- Provide analytics on documentation usage, such as frequently accessed sections or outdated pages. +- Implement feedback mechanisms for readers to suggest improvements or report issues with the documentation. ##### Phase 4: Scalability and Deployment 1. **Cloud Integration** - - Enable cloud-based processing for heavy documentation compilation tasks to reduce local resource consumption. - - Support for storing and serving compiled documentation from cloud storage solutions. + +- Enable cloud-based processing for heavy documentation compilation tasks to reduce local resource consumption. +- Support for storing and serving compiled documentation from cloud storage solutions. 2. **Continuous Integration/Continuous Deployment (CI/CD) Integration** - - Develop plugins or extensions for popular CI/CD tools to automate documentation compilation and deployment as part of the software release process. - - Implement checks to ensure documentation is up-to-date with the codebase before deployment. + +- Develop plugins or extensions for popular CI/CD tools to automate documentation compilation and deployment as part of the software release process. +- Implement checks to ensure documentation is up-to-date with the codebase before deployment. 3. **Enterprise Features** - - Add support for Single Sign-On (SSO) and role-based access control for large teams and organizations. - - Implement audit logs and compliance features for enterprise usage. -This roadmap is subject to change based on user feedback and technological advancements. The goal is to make `GenerateDocumentationAction` a comprehensive tool that simplifies the process of generating and maintaining high-quality documentation for software projects. +- Add support for Single Sign-On (SSO) and role-based access control for large teams and organizations. +- Implement audit logs and compliance features for enterprise usage. -# resources\sources\kt\com\github\simiacryptus\aicoder\ApplicationEvents.kt +This roadmap is subject to change based on user feedback and technological advancements. The goal is to make `GenerateDocumentationAction` a comprehensive tool +that simplifies the process of generating and maintaining high-quality documentation for software projects. -Creating a feature development roadmap for the `ApplicationEvents` class within the `com.github.simiacryptus.aicoder` package involves outlining the future enhancements, improvements, and additions planned for this component. The roadmap will guide the development process, ensuring that the class evolves to meet the needs of its users effectively. Here's a proposed roadmap: +# resources\sources\kt\com\github\simiacryptus\aicoder\ApplicationEvents.kt +Creating a feature development roadmap for the `ApplicationEvents` class within the `com.simiacryptus.aicoder` package involves outlining the future +enhancements, improvements, and additions planned for this component. The roadmap will guide the development process, ensuring that the class evolves to meet +the needs of its users effectively. Here's a proposed roadmap: #### Phase 1: Initial Setup and Integration -- **Complete Initial Development**: Finalize the current implementation of the `ApplicationEvents` class, ensuring it integrates well with the IntelliJ platform and other components of the system. -- **Testing and Debugging**: Conduct thorough testing to identify and fix any bugs or issues in the current implementation. This includes unit tests, integration tests, and manual testing within the IDE. -- **Documentation**: Create comprehensive documentation covering the class's functionality, usage examples, and integration steps for developers. +- **Complete Initial Development**: Finalize the current implementation of the `ApplicationEvents` class, ensuring it integrates well with the IntelliJ platform + and other components of the system. +- **Testing and Debugging**: Conduct thorough testing to identify and fix any bugs or issues in the current implementation. This includes unit tests, + integration tests, and manual testing within the IDE. +- **Documentation**: Create comprehensive documentation covering the class's functionality, usage examples, and integration steps for developers. #### Phase 2: Enhancements and Features -- **Performance Optimization**: Analyze and optimize the performance of the `ApplicationEvents` class, ensuring minimal impact on the IDE's startup time and overall performance. -- **Extend Interceptor Capabilities**: Enhance the `OutputInterceptor` setup to support more granular control over intercepted output, including filtering and redirection options. -- **Improve Client Management**: Develop more sophisticated client management strategies within `ApplicationServices.clientManager`, including support for multiple clients and session management. +- **Performance Optimization**: Analyze and optimize the performance of the `ApplicationEvents` class, ensuring minimal impact on the IDE's startup time and + overall performance. +- **Extend Interceptor Capabilities**: Enhance the `OutputInterceptor` setup to support more granular control over intercepted output, including filtering and + redirection options. +- **Improve Client Management**: Develop more sophisticated client management strategies within `ApplicationServices.clientManager`, including support for + multiple clients and session management. #### Phase 3: Security and Compliance -- **Enhanced Authentication and Authorization**: Strengthen the security model by implementing more robust authentication and authorization mechanisms. This could include support for OAuth, JWT tokens, or integration with third-party identity providers. -- **Audit Logging**: Implement comprehensive audit logging for all significant events and operations, aiding in troubleshooting and compliance with security policies. -- **Data Privacy Compliance**: Ensure the class and its dependencies comply with relevant data privacy regulations (e.g., GDPR, CCPA) by implementing necessary data handling and privacy features. +- **Enhanced Authentication and Authorization**: Strengthen the security model by implementing more robust authentication and authorization mechanisms. This + could include support for OAuth, JWT tokens, or integration with third-party identity providers. +- **Audit Logging**: Implement comprehensive audit logging for all significant events and operations, aiding in troubleshooting and compliance with security + policies. +- **Data Privacy Compliance**: Ensure the class and its dependencies comply with relevant data privacy regulations (e.g., GDPR, CCPA) by implementing necessary + data handling and privacy features. #### Phase 4: User Experience and Usability -- **User Interface for Settings**: Develop a user-friendly interface within the IDE settings to configure and manage the features provided by `ApplicationEvents` and its related services. + +- **User Interface for Settings**: Develop a user-friendly interface within the IDE settings to configure and manage the features provided by + `ApplicationEvents` and its related services. - **Feedback Mechanism**: Implement a mechanism for users to provide feedback directly from the IDE, facilitating continuous improvement based on user input. - **Localization and Internationalization**: Prepare the class and its user-facing components for localization, making it accessible to a global audience. - #### Phase 5: Expansion and Integration -- **Plugin Ecosystem Integration**: Explore opportunities for integrating with other plugins and services within the IntelliJ ecosystem, enhancing the functionality and utility of the `ApplicationEvents` class. -- **API for Third-party Extensions**: Develop a public API that allows third-party developers to extend and customize the functionality provided by `ApplicationEvents`, fostering an ecosystem of extensions and plugins. -- **Cross-IDE Support**: Investigate the feasibility of adapting the class for use in other IDEs (e.g., Eclipse, VS Code), expanding its reach and utility across the developer community. +- **Plugin Ecosystem Integration**: Explore opportunities for integrating with other plugins and services within the IntelliJ ecosystem, enhancing the + functionality and utility of the `ApplicationEvents` class. +- **API for Third-party Extensions**: Develop a public API that allows third-party developers to extend and customize the functionality provided by + `ApplicationEvents`, fostering an ecosystem of extensions and plugins. +- **Cross-IDE Support**: Investigate the feasibility of adapting the class for use in other IDEs (e.g., Eclipse, VS Code), expanding its reach and utility + across the developer community. #### Phase 6: Continuous Improvement and Support + - **Regular Updates**: Commit to a regular update schedule, incorporating bug fixes, performance improvements, and feature enhancements. -- **Community Engagement**: Engage with the developer community through forums, social media, and conferences to gather feedback, offer support, and promote the class's capabilities. -- **Long-term Support Strategy**: Develop a long-term support strategy, including versioning policies, backward compatibility considerations, and deprecation plans for outdated features. +- **Community Engagement**: Engage with the developer community through forums, social media, and conferences to gather feedback, offer support, and promote the + class's capabilities. +- **Long-term Support Strategy**: Develop a long-term support strategy, including versioning policies, backward compatibility considerations, and deprecation + plans for outdated features. This roadmap is a living document and should be revisited and revised regularly based on user feedback, technological advancements, and strategic priorities. # resources\sources\kt\com\github\simiacryptus\aicoder\actions\markdown\MarkdownImplementActionGroup.kt - #### Feature Development Roadmap for Markdown Implement Action Group -The development roadmap for the Markdown Implement Action Group outlines the planned enhancements, new features, and improvements to the existing codebase. This roadmap is designed to guide the development process, ensuring that the project evolves to meet the needs of its users while maintaining high standards of quality and performance. - +The development roadmap for the Markdown Implement Action Group outlines the planned enhancements, new features, and improvements to the existing codebase. This +roadmap is designed to guide the development process, ensuring that the project evolves to meet the needs of its users while maintaining high standards of +quality and performance. ##### Phase 1: Initial Setup and Core Functionality 1. **Codebase Setup** - - Set up the project repository and define the initial project structure. - - Establish coding standards and guidelines for contributors. + +- Set up the project repository and define the initial project structure. +- Establish coding standards and guidelines for contributors. 2. **Core Functionality Development** - - Implement the base `MarkdownImplementActionGroup` class to manage action groups. - - Develop the `MarkdownImplementAction` class to handle the conversion of selected text into different programming languages within Markdown code blocks. - - Integrate a list of supported programming languages for Markdown code blocks. + +- Implement the base `MarkdownImplementActionGroup` class to manage action groups. +- Develop the `MarkdownImplementAction` class to handle the conversion of selected text into different programming languages within Markdown code blocks. +- Integrate a list of supported programming languages for Markdown code blocks. 3. **Integration with Conversion API** - - Establish a connection with the `ConversionAPI` to convert selected text into the specified programming language code. - - Implement error handling and retries for API requests. + +- Establish a connection with the `ConversionAPI` to convert selected text into the specified programming language code. +- Implement error handling and retries for API requests. 4. **User Interface and Experience** - - Enhance the UI to provide a seamless experience for users when selecting text and converting it into code blocks. - - Implement feedback mechanisms for successful and unsuccessful conversions. +- Enhance the UI to provide a seamless experience for users when selecting text and converting it into code blocks. +- Implement feedback mechanisms for successful and unsuccessful conversions. ##### Phase 2: Expansion and Enhancement 1. **Support for Additional Languages** - - Evaluate and add more programming languages to the supported languages list based on user feedback and demand. - - Ensure the conversion accuracy and quality for newly supported languages. + +- Evaluate and add more programming languages to the supported languages list based on user feedback and demand. +- Ensure the conversion accuracy and quality for newly supported languages. 2. **Performance Optimization** - - Optimize the performance of the conversion process to handle large selections of text efficiently. - - Reduce the latency in fetching conversion results from the `ConversionAPI`. + +- Optimize the performance of the conversion process to handle large selections of text efficiently. +- Reduce the latency in fetching conversion results from the `ConversionAPI`. 3. **Advanced Configuration Options** - - Allow users to customize the behavior of the Markdown Implement Action Group through settings, such as default language preferences and conversion temperature. - - Implement project-specific settings to cater to different project requirements. +- Allow users to customize the behavior of the Markdown Implement Action Group through settings, such as default language preferences and conversion + temperature. +- Implement project-specific settings to cater to different project requirements. ##### Phase 3: User Feedback and Continuous Improvement 1. **User Feedback Collection** - - Implement mechanisms to collect user feedback directly within the plugin. - - Analyze feedback to identify common issues, requested features, and areas for improvement. + +- Implement mechanisms to collect user feedback directly within the plugin. +- Analyze feedback to identify common issues, requested features, and areas for improvement. 2. **Feature Enhancements Based on Feedback** - - Prioritize and implement feature enhancements and improvements based on user feedback. - - Continuously monitor the impact of changes on user satisfaction and plugin performance. + +- Prioritize and implement feature enhancements and improvements based on user feedback. +- Continuously monitor the impact of changes on user satisfaction and plugin performance. 3. **Documentation and Support** - - Develop comprehensive documentation covering setup, usage, and troubleshooting. - - Establish a support channel for users to report issues and seek assistance. +- Develop comprehensive documentation covering setup, usage, and troubleshooting. +- Establish a support channel for users to report issues and seek assistance. ##### Phase 4: Future Directions 1. **AI-Assisted Code Generation** - - Explore the integration of AI-based code generation features to assist users in creating code blocks from natural language descriptions. - - Evaluate the feasibility and user demand for such features. + +- Explore the integration of AI-based code generation features to assist users in creating code blocks from natural language descriptions. +- Evaluate the feasibility and user demand for such features. 2. **Collaboration and Sharing** - - Implement features to facilitate the sharing of converted code blocks among team members or within the developer community. - - Explore integration with version control systems for seamless collaboration. + +- Implement features to facilitate the sharing of converted code blocks among team members or within the developer community. +- Explore integration with version control systems for seamless collaboration. 3. **Plugin Ecosystem Integration** - - Investigate opportunities for integrating the Markdown Implement Action Group with other plugins and tools within the developer ecosystem. - - Enhance interoperability and data exchange capabilities to enrich the user experience. -This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The development team is committed to delivering high-quality features that add value to the user experience while maintaining the flexibility to adapt to emerging needs and opportunities. +- Investigate opportunities for integrating the Markdown Implement Action Group with other plugins and tools within the developer ecosystem. +- Enhance interoperability and data exchange capabilities to enrich the user experience. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\SelectionAction.kt +This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The development team is committed to delivering +high-quality features that add value to the user experience while maintaining the flexibility to adapt to emerging needs and opportunities. -Creating a feature development roadmap for the `SelectionAction` class and its associated functionalities involves outlining a series of steps and enhancements that can be made to improve its capabilities, usability, and integration within the IntelliJ platform. The roadmap will be divided into short-term, mid-term, and long-term goals, each with specific features and improvements to be implemented. +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\SelectionAction.kt +Creating a feature development roadmap for the `SelectionAction` class and its associated functionalities involves outlining a series of steps and enhancements +that can be made to improve its capabilities, usability, and integration within the IntelliJ platform. The roadmap will be divided into short-term, mid-term, +and long-term goals, each with specific features and improvements to be implemented. #### Short-Term Goals (1-3 Months) 1. **Refinement of Selection Mechanisms** - - Improve the `retarget` method to handle edge cases more gracefully, ensuring selections are always valid and meaningful. - - Enhance the `defaultSelection` and `editSelection` methods to support more complex selection scenarios, such as code blocks or specific syntax patterns. + +- Improve the `retarget` method to handle edge cases more gracefully, ensuring selections are always valid and meaningful. +- Enhance the `defaultSelection` and `editSelection` methods to support more complex selection scenarios, such as code blocks or specific syntax patterns. 2. **UI Improvements** - - Develop a more intuitive UI for configuring the action settings, making it easier for users to specify their preferences without diving into code. - - Implement visual feedback in the editor for the selected range, especially when the selection is automatically adjusted by the action. + +- Develop a more intuitive UI for configuring the action settings, making it easier for users to specify their preferences without diving into code. +- Implement visual feedback in the editor for the selected range, especially when the selection is automatically adjusted by the action. 3. **Performance Optimization** - - Profile the action's performance, especially in large files, and optimize the code to reduce latency. - - Ensure that the action does not block the UI thread, providing a smooth user experience. +- Profile the action's performance, especially in large files, and optimize the code to reduce latency. +- Ensure that the action does not block the UI thread, providing a smooth user experience. #### Mid-Term Goals (4-6 Months) 1. **Language Support Expansion** - - Extend the `isLanguageSupported` method to include more programming languages, broadening the utility of the action across different types of projects. - - Implement language-specific selection strategies to handle unique syntax and structure efficiently. + +- Extend the `isLanguageSupported` method to include more programming languages, broadening the utility of the action across different types of projects. +- Implement language-specific selection strategies to handle unique syntax and structure efficiently. 2. **Context-Aware Enhancements** - - Improve the `contextRanges` method to identify and utilize more detailed context information, enabling smarter selection adjustments based on the surrounding code. - - Develop a feature to suggest actions or refactorings based on the selected code and its context. + +- Improve the `contextRanges` method to identify and utilize more detailed context information, enabling smarter selection adjustments based on the + surrounding code. +- Develop a feature to suggest actions or refactorings based on the selected code and its context. 3. **Integration with Other Tools** - - Create APIs or hooks that allow other plugins or tools to interact with or extend the `SelectionAction` functionalities. - - Explore integration possibilities with version control systems to facilitate actions like partial commits or code reviews. +- Create APIs or hooks that allow other plugins or tools to interact with or extend the `SelectionAction` functionalities. +- Explore integration possibilities with version control systems to facilitate actions like partial commits or code reviews. #### Long-Term Goals (7-12 Months) 1. **Machine Learning Assisted Selections** - - Investigate the use of machine learning models to predict and adjust selections based on user behavior and common patterns in code structure. - - Implement a feedback loop where the action learns from user adjustments to improve its selection predictions over time. + +- Investigate the use of machine learning models to predict and adjust selections based on user behavior and common patterns in code structure. +- Implement a feedback loop where the action learns from user adjustments to improve its selection predictions over time. 2. **Collaborative Features** - - Develop features that allow teams to share and synchronize selection actions or configurations, promoting consistency across a project or organization. - - Explore the possibility of real-time collaboration features, where selections can be shared or mirrored between users in a pair programming scenario. + +- Develop features that allow teams to share and synchronize selection actions or configurations, promoting consistency across a project or organization. +- Explore the possibility of real-time collaboration features, where selections can be shared or mirrored between users in a pair programming scenario. 3. **Extensive Customization and Scripting Support** - - Allow users to write custom scripts or plugins that can modify or extend the selection logic, providing a powerful tool for developers to tailor the action to their specific needs. - - Implement a sandbox environment where users can safely test and debug their custom scripts. +- Allow users to write custom scripts or plugins that can modify or extend the selection logic, providing a powerful tool for developers to tailor the action + to their specific needs. +- Implement a sandbox environment where users can safely test and debug their custom scripts. #### Continuous Improvement - **User Feedback and Community Involvement** - - Establish channels for user feedback and actively involve the community in the development process, prioritizing features and improvements based on user needs. + - Establish channels for user feedback and actively involve the community in the development process, prioritizing features and improvements based on user + needs. - **Documentation and Tutorials** - Continuously update the documentation and provide tutorials or examples to help users understand and leverage the full capabilities of the action. -This roadmap provides a structured approach to developing the `SelectionAction` class, focusing on immediate improvements, expanding capabilities, and exploring innovative features in the long term. +This roadmap provides a structured approach to developing the `SelectionAction` class, focusing on immediate improvements, expanding capabilities, and exploring +innovative features in the long term. # resources\sources\kt\com\github\simiacryptus\aicoder\config\ActionSettingsRegistry.kt -Creating a feature development roadmap for the `ActionSettingsRegistry` class involves outlining the planned enhancements, improvements, and new features that will be added to the class over time. This roadmap will help guide development efforts and communicate the future direction of the project to stakeholders. Here's a proposed roadmap based on the current state and potential enhancements for the `ActionSettingsRegistry` class: - +Creating a feature development roadmap for the `ActionSettingsRegistry` class involves outlining the planned enhancements, improvements, and new features that +will be added to the class over time. This roadmap will help guide development efforts and communicate the future direction of the project to stakeholders. +Here's a proposed roadmap based on the current state and potential enhancements for the `ActionSettingsRegistry` class: #### Phase 1: Refinement and Optimization -- **Code Cleanup and Documentation**: Start by refining the existing codebase, ensuring that all methods and classes are well-documented. This includes adding comments to explain complex logic and ensuring that the code follows Kotlin best practices. -- **Performance Optimization**: Analyze the performance of the current implementation, identifying any bottlenecks or inefficient code paths. Optimize these areas for better performance, especially focusing on the `edit` method which seems to be central to the functionality. +- **Code Cleanup and Documentation**: Start by refining the existing codebase, ensuring that all methods and classes are well-documented. This includes adding + comments to explain complex logic and ensuring that the code follows Kotlin best practices. +- **Performance Optimization**: Analyze the performance of the current implementation, identifying any bottlenecks or inefficient code paths. Optimize these + areas for better performance, especially focusing on the `edit` method which seems to be central to the functionality. #### Phase 2: Feature Enhancements -- **UI Integration**: Enhance the integration with the IntelliJ platform UI, making it easier for users to interact with the action settings. This could include more intuitive menus, better feedback on action changes, and a more seamless experience when editing action configurations. -- **Dynamic Action Enhancements**: Improve the support for dynamic actions, making it easier to create, edit, and manage them. This could involve better error handling, more intuitive APIs for action creation, and enhanced support for different programming languages. -- **Version Control Integration**: Integrate the action settings with version control systems (e.g., Git) to allow for better tracking of changes, easier rollback of configurations, and collaboration among multiple developers. +- **UI Integration**: Enhance the integration with the IntelliJ platform UI, making it easier for users to interact with the action settings. This could include + more intuitive menus, better feedback on action changes, and a more seamless experience when editing action configurations. +- **Dynamic Action Enhancements**: Improve the support for dynamic actions, making it easier to create, edit, and manage them. This could involve better error + handling, more intuitive APIs for action creation, and enhanced support for different programming languages. +- **Version Control Integration**: Integrate the action settings with version control systems (e.g., Git) to allow for better tracking of changes, easier + rollback of configurations, and collaboration among multiple developers. #### Phase 3: New Features -- **Action Sharing and Marketplace**: Develop a platform or marketplace where users can share their custom actions with others. This would involve creating a repository of actions, mechanisms for sharing and importing actions, and possibly a rating or review system. -- **Advanced Configuration Options**: Introduce more advanced configuration options for actions, allowing users to customize their behavior in more detailed ways. This could include conditional execution, integration with external tools or scripts, and user-defined variables. -- **Analytics and Usage Insights**: Implement analytics to gather insights on how actions are being used. This could help identify popular actions, usage patterns, and potential areas for improvement. Privacy considerations should be taken into account when designing this feature. +- **Action Sharing and Marketplace**: Develop a platform or marketplace where users can share their custom actions with others. This would involve creating a + repository of actions, mechanisms for sharing and importing actions, and possibly a rating or review system. +- **Advanced Configuration Options**: Introduce more advanced configuration options for actions, allowing users to customize their behavior in more detailed + ways. This could include conditional execution, integration with external tools or scripts, and user-defined variables. +- **Analytics and Usage Insights**: Implement analytics to gather insights on how actions are being used. This could help identify popular actions, usage + patterns, and potential areas for improvement. Privacy considerations should be taken into account when designing this feature. #### Phase 4: Scalability and Extensibility -- **Plugin Architecture**: Refactor the codebase to support a plugin architecture, allowing third-party developers to extend the functionality of the action settings with their own plugins. This would make the system more flexible and open to customization. -- **Cloud Integration**: Explore options for cloud integration, allowing users to sync their action settings across multiple devices or share them with a team. This would require secure authentication and data storage solutions. -- **Internationalization and Localization**: Prepare the codebase for internationalization, making it easy to translate the UI and messages into different languages. This would make the tool more accessible to a global audience. +- **Plugin Architecture**: Refactor the codebase to support a plugin architecture, allowing third-party developers to extend the functionality of the action + settings with their own plugins. This would make the system more flexible and open to customization. +- **Cloud Integration**: Explore options for cloud integration, allowing users to sync their action settings across multiple devices or share them with a team. + This would require secure authentication and data storage solutions. +- **Internationalization and Localization**: Prepare the codebase for internationalization, making it easy to translate the UI and messages into different + languages. This would make the tool more accessible to a global audience. #### Phase 5: Long-term Vision -- **AI-Assisted Code Generation**: Investigate the integration of AI technologies to assist in generating action code based on natural language descriptions or other high-level inputs. This could significantly speed up the development of custom actions. -- **Comprehensive Testing Framework**: Develop a comprehensive testing framework for actions, allowing developers to write and run tests to ensure their actions work as expected across different environments and scenarios. -- **Community Engagement**: Foster a community around the tool, encouraging feedback, contributions, and collaboration. This could involve setting up forums, contributing guides, and regular community events. -This roadmap is a living document and should be revisited and revised regularly based on feedback from users, technological advancements, and the changing needs of the project. +- **AI-Assisted Code Generation**: Investigate the integration of AI technologies to assist in generating action code based on natural language descriptions or + other high-level inputs. This could significantly speed up the development of custom actions. +- **Comprehensive Testing Framework**: Develop a comprehensive testing framework for actions, allowing developers to write and run tests to ensure their actions + work as expected across different environments and scenarios. +- **Community Engagement**: Foster a community around the tool, encouraging feedback, contributions, and collaboration. This could involve setting up forums, + contributing guides, and regular community events. -# resources\sources\kt\com\github\simiacryptus\aicoder\config\ActionTable.kt +This roadmap is a living document and should be revisited and revised regularly based on feedback from users, technological advancements, and the changing needs +of the project. -The code provided outlines a `ActionTable` class, which is a component of a larger application, likely an IDE plugin given the use of IntelliJ's API. This class manages a table UI for action settings, allowing users to view, edit, clone, and remove actions. Based on this, a feature development roadmap can be structured to enhance and expand the capabilities of this component and potentially the broader application it belongs to. The roadmap will be divided into short-term, medium-term, and long-term goals. +# resources\sources\kt\com\github\simiacryptus\aicoder\config\ActionTable.kt +The code provided outlines a `ActionTable` class, which is a component of a larger application, likely an IDE plugin given the use of IntelliJ's API. This class +manages a table UI for action settings, allowing users to view, edit, clone, and remove actions. Based on this, a feature development roadmap can be structured +to enhance and expand the capabilities of this component and potentially the broader application it belongs to. The roadmap will be divided into short-term, +medium-term, and long-term goals. #### Short-Term Goals (1-3 Months) 1. **UI Improvements:** - - Enhance table UI responsiveness and aesthetics. - - Implement better validation feedback for user inputs in the clone and edit dialogs. + +- Enhance table UI responsiveness and aesthetics. +- Implement better validation feedback for user inputs in the clone and edit dialogs. 2. **Performance Optimization:** - - Optimize the read and write operations to handle larger datasets without performance degradation. - - Implement lazy loading for action settings if the dataset becomes significantly large. + +- Optimize the read and write operations to handle larger datasets without performance degradation. +- Implement lazy loading for action settings if the dataset becomes significantly large. 3. **Bug Fixes:** - - Address any known bugs related to the action table's CRUD operations. - - Ensure compatibility with the latest version of the IntelliJ platform. +- Address any known bugs related to the action table's CRUD operations. +- Ensure compatibility with the latest version of the IntelliJ platform. #### Medium-Term Goals (4-6 Months) 1. **Feature Expansion:** - - Introduce a search/filter feature to easily locate actions within the table. - - Add multi-select capabilities to clone and remove actions in batches. + +- Introduce a search/filter feature to easily locate actions within the table. +- Add multi-select capabilities to clone and remove actions in batches. 2. **Integration Enhancements:** - - Develop an API for other plugins to interact with the action table, allowing for extensibility. - - Implement a mechanism to automatically update action settings from an external source or repository. + +- Develop an API for other plugins to interact with the action table, allowing for extensibility. +- Implement a mechanism to automatically update action settings from an external source or repository. 3. **User Experience:** - - Add a preview feature to view the outcome of an action before applying it. - - Implement undo/redo functionality for action modifications. +- Add a preview feature to view the outcome of an action before applying it. +- Implement undo/redo functionality for action modifications. #### Long-Term Goals (7-12 Months) 1. **Scalability:** - - Design and implement a scalable backend (if applicable) to store action settings, supporting collaboration among multiple users. - - Explore the possibility of cloud-based synchronization of action settings across different installations. + +- Design and implement a scalable backend (if applicable) to store action settings, supporting collaboration among multiple users. +- Explore the possibility of cloud-based synchronization of action settings across different installations. 2. **Advanced Customization:** - - Allow users to create custom action categories for better organization. - - Implement a scripting interface for users to define custom actions or extend existing ones with custom logic. + +- Allow users to create custom action categories for better organization. +- Implement a scripting interface for users to define custom actions or extend existing ones with custom logic. 3. **Community and Collaboration:** - - Develop a community portal where users can share and discover custom actions created by others. - - Integrate with version control systems to enable versioning and sharing of action configurations within teams. + +- Develop a community portal where users can share and discover custom actions created by others. +- Integrate with version control systems to enable versioning and sharing of action configurations within teams. 4. **Analytics and Insights:** - - Introduce analytics to track the usage and performance of actions, providing insights to users for optimization. - - Implement feedback mechanisms within the plugin to gather user suggestions and issues for continuous improvement. -This roadmap aims to progressively enhance the `ActionTable` component's functionality, usability, and integration capabilities, ultimately enriching the user experience and fostering a collaborative community around the tool. +- Introduce analytics to track the usage and performance of actions, providing insights to users for optimization. +- Implement feedback mechanisms within the plugin to gather user suggestions and issues for continuous improvement. -# resources\sources\kt\com\github\simiacryptus\aicoder\actions\markdown\MarkdownListAction.kt +This roadmap aims to progressively enhance the `ActionTable` component's functionality, usability, and integration capabilities, ultimately enriching the user +experience and fostering a collaborative community around the tool. +# resources\sources\kt\com\github\simiacryptus\aicoder\actions\markdown\MarkdownListAction.kt #### Feature Development Roadmap for MarkdownListAction -The `MarkdownListAction` class is designed to enhance the functionality of markdown editing within an IDE, specifically targeting the generation and manipulation of markdown lists. The roadmap for developing and enhancing this feature is outlined below, divided into phases for clarity and structured progression. - +The `MarkdownListAction` class is designed to enhance the functionality of markdown editing within an IDE, specifically targeting the generation and +manipulation of markdown lists. The roadmap for developing and enhancing this feature is outlined below, divided into phases for clarity and structured +progression. ##### Phase 1: Initial Setup and Basic Functionality - **Task 1.1:** Implement the basic structure of the `MarkdownListAction` class, extending the `BaseAction` to inherit common action properties and methods. - **Task 1.2:** Develop the `ListAPI` interface to define the contract for generating new list items based on existing items and a specified count. -- **Task 1.3:** Integrate `ChatProxy` to utilize AI models for generating list content dynamically, ensuring the setup supports retries and model selection based on app settings. - +- **Task 1.3:** Integrate `ChatProxy` to utilize AI models for generating list content dynamically, ensuring the setup supports retries and model selection + based on app settings. ##### Phase 2: Integration with IDE and Markdown Parsing -- **Task 2.1:** Implement the `handle` method to interact with the IDE's editor, caret, and PSI (Program Structure Interface) file to identify the context of the action. -- **Task 2.2:** Utilize utility methods from `UITools` and `PsiUtil` to parse the markdown structure, specifically identifying lists and list items within the markdown document. +- **Task 2.1:** Implement the `handle` method to interact with the IDE's editor, caret, and PSI (Program Structure Interface) file to identify the context of + the action. +- **Task 2.2:** Utilize utility methods from `UITools` and `PsiUtil` to parse the markdown structure, specifically identifying lists and list items within the + markdown document. - **Task 2.3:** Develop logic to extract existing list items, determine their indentation and bullet types, and prepare them for processing. - ##### Phase 3: Dynamic List Item Generation - **Task 3.1:** Implement the interaction with the `ListAPI` through the `proxy` property to generate new list items based on the existing items. -- **Task 3.2:** Process the generated list items, applying the appropriate indentation and bullet types to maintain consistency with the existing list structure. -- **Task 3.3:** Insert the newly generated list items into the document at the correct location, ensuring the action does not disrupt the existing content structure. - +- **Task 3.2:** Process the generated list items, applying the appropriate indentation and bullet types to maintain consistency with the existing list + structure. +- **Task 3.3:** Insert the newly generated list items into the document at the correct location, ensuring the action does not disrupt the existing content + structure. ##### Phase 4: Usability and Performance Enhancements @@ -4672,13 +5758,12 @@ The `MarkdownListAction` class is designed to enhance the functionality of markd - **Task 4.2:** Implement error handling and retries for the interaction with the `ListAPI`, ensuring robustness in case of failures. - **Task 4.3:** Enhance the user interface and feedback mechanisms, providing clear indications of the action's progress and any issues encountered. - ##### Phase 5: Testing, Documentation, and Release - **Task 5.1:** Conduct comprehensive testing, covering various markdown structures, list types, and edge cases to ensure reliability and correctness. - **Task 5.2:** Prepare detailed documentation, including usage instructions, configuration options, and troubleshooting tips. -- **Task 5.3:** Package and release the updated feature, coordinating with the broader application release cycle and ensuring compatibility with the target IDE versions. - +- **Task 5.3:** Package and release the updated feature, coordinating with the broader application release cycle and ensuring compatibility with the target IDE + versions. ##### Phase 6: Feedback Loop and Continuous Improvement @@ -4686,480 +5771,573 @@ The `MarkdownListAction` class is designed to enhance the functionality of markd - **Task 6.2:** Analyze feedback and usage data to identify areas for improvement, new feature requests, and potential issues. - **Task 6.3:** Plan and implement updates based on feedback, continuously enhancing the feature in response to user needs and technological advancements. -This roadmap provides a structured approach to developing the `MarkdownListAction` feature, ensuring it meets the needs of users while maintaining high standards of quality and performance. +This roadmap provides a structured approach to developing the `MarkdownListAction` feature, ensuring it meets the needs of users while maintaining high +standards of quality and performance. # resources\sources\kt\com\github\simiacryptus\aicoder\config\AppSettingsConfigurable.kt -Developing a feature for a software project involves planning and executing various tasks. Below is a feature development roadmap for enhancing the `AppSettingsConfigurable` class, which is part of a larger project aimed at managing application settings through a user interface. This roadmap outlines the steps from initial planning to the final release and maintenance. - +Developing a feature for a software project involves planning and executing various tasks. Below is a feature development roadmap for enhancing the +`AppSettingsConfigurable` class, which is part of a larger project aimed at managing application settings through a user interface. This roadmap outlines the +steps from initial planning to the final release and maintenance. #### Phase 1: Planning and Design -1. **Requirement Analysis**: Gather and analyze requirements for the new feature. This involves understanding what enhancements or new functionalities need to be added to the `AppSettingsConfigurable` class. -2. **Feasibility Study**: Assess the technical feasibility of the proposed feature, including any dependencies on external libraries or services. -3. **Design Specification**: Create detailed design documents specifying how the new feature will be implemented, including UI changes, data models, and interaction with other components. +1. **Requirement Analysis**: Gather and analyze requirements for the new feature. This involves understanding what enhancements or new functionalities need to + be added to the `AppSettingsConfigurable` class. +2. **Feasibility Study**: Assess the technical feasibility of the proposed feature, including any dependencies on external libraries or services. +3. **Design Specification**: Create detailed design documents specifying how the new feature will be implemented, including UI changes, data models, and + interaction with other components. #### Phase 2: Development + 4. **Setup Development Environment**: Ensure all developers have the necessary tools and access to resources required for development. 5. **Implementation**: Start coding the new feature based on the design specifications. This includes: - - Enhancing the `read` and `write` methods to support additional settings. - - Improving the `newComponent` and `newSettings` methods for better initialization. - - Adding new UI components or functionalities as needed. -6. **Code Review**: Conduct regular code reviews to ensure code quality and adherence to project standards. +- Enhancing the `read` and `write` methods to support additional settings. +- Improving the `newComponent` and `newSettings` methods for better initialization. +- Adding new UI components or functionalities as needed. + +6. **Code Review**: Conduct regular code reviews to ensure code quality and adherence to project standards. #### Phase 3: Testing + 7. **Unit Testing**: Write and execute unit tests for the new feature to ensure individual components work as expected. 8. **Integration Testing**: Test the integration of the new feature with existing components to ensure they work together seamlessly. 9. **User Acceptance Testing (UAT)**: Allow end-users to test the new feature and collect feedback for any adjustments. - #### Phase 4: Deployment + 10. **Preparation**: Prepare the deployment environment, ensuring all prerequisites are met. 11. **Deployment**: Deploy the new feature to the production environment. 12. **Post-Deployment Testing**: Conduct thorough testing in the production environment to ensure the feature works as expected. - #### Phase 5: Release + 13. **Release Announcement**: Announce the release of the new feature to users through appropriate channels. 14. **Documentation**: Update the project documentation to include information about the new feature and how to use it. - #### Phase 6: Maintenance and Feedback + 15. **Monitor and Fix Issues**: Monitor the feature for any issues or bugs and address them promptly. 16. **Collect Feedback**: Continuously collect feedback from users to understand how the feature can be improved. 17. **Iterative Improvement**: Based on feedback, plan and implement improvements in future iterations. -This roadmap provides a structured approach to developing a new feature for the `AppSettingsConfigurable` class, ensuring that all aspects of the development process are covered, from planning to release and maintenance. +This roadmap provides a structured approach to developing a new feature for the `AppSettingsConfigurable` class, ensuring that all aspects of the development +process are covered, from planning to release and maintenance. # resources\sources\kt\com\github\simiacryptus\aicoder\config\AppSettingsState.kt -Creating a feature development roadmap for the `AppSettingsState` class involves planning out enhancements, new features, and improvements to the existing codebase. This roadmap will guide the development process, ensuring that the project evolves in a structured and efficient manner. Here's a proposed roadmap based on the current state and potential enhancements to the `AppSettingsState` class: - +Creating a feature development roadmap for the `AppSettingsState` class involves planning out enhancements, new features, and improvements to the existing +codebase. This roadmap will guide the development process, ensuring that the project evolves in a structured and efficient manner. Here's a proposed roadmap +based on the current state and potential enhancements to the `AppSettingsState` class: #### Phase 1: Refinement and Optimization -- **Code Cleanup and Documentation**: Start by refining the existing codebase. This includes adding comprehensive comments, improving variable names for clarity, and removing any redundant code. Ensure that every method and class variable is well-documented. -- **Performance Optimization**: Analyze the performance of the current implementation, focusing on the `loadState` and `getState` methods. Optimize JSON serialization and deserialization processes to enhance performance. +- **Code Cleanup and Documentation**: Start by refining the existing codebase. This includes adding comprehensive comments, improving variable names for + clarity, and removing any redundant code. Ensure that every method and class variable is well-documented. +- **Performance Optimization**: Analyze the performance of the current implementation, focusing on the `loadState` and `getState` methods. Optimize JSON + serialization and deserialization processes to enhance performance. #### Phase 2: Feature Enhancements -- **UI Integration for Settings**: Develop a user-friendly interface within the IntelliJ plugin settings to allow users to modify `AppSettingsState` properties without directly editing the XML or JSON files. -- **Expand Model Support**: Introduce support for additional OpenAI models. Allow users to select and configure multiple models from the plugin settings UI. -- **Enhanced Language Support**: Extend the `humanLanguage` property to support more languages. Implement a feature that automatically detects and suggests the language based on the user's locale or project settings. +- **UI Integration for Settings**: Develop a user-friendly interface within the IntelliJ plugin settings to allow users to modify `AppSettingsState` properties + without directly editing the XML or JSON files. +- **Expand Model Support**: Introduce support for additional OpenAI models. Allow users to select and configure multiple models from the plugin settings UI. +- **Enhanced Language Support**: Extend the `humanLanguage` property to support more languages. Implement a feature that automatically detects and suggests the + language based on the user's locale or project settings. #### Phase 3: Advanced Functionality -- **Command History Management**: Enhance the management of recent commands with features like command history export/import, categorization of commands, and advanced MRU (Most Recently Used) strategies. -- **Action Settings Customization**: Provide a more advanced interface for customizing editor and file actions. Allow users to create custom action sets and share them with the community. -- **API Usage Monitoring**: Implement a feature to monitor and display API usage statistics, including token consumption, request counts, and error rates. Introduce alerts for approaching API key limits. +- **Command History Management**: Enhance the management of recent commands with features like command history export/import, categorization of commands, and + advanced MRU (Most Recently Used) strategies. +- **Action Settings Customization**: Provide a more advanced interface for customizing editor and file actions. Allow users to create custom action sets and + share them with the community. +- **API Usage Monitoring**: Implement a feature to monitor and display API usage statistics, including token consumption, request counts, and error rates. + Introduce alerts for approaching API key limits. #### Phase 4: Security and Reliability -- **Secure API Key Storage**: Enhance the security of API key storage using encryption or integration with secure vaults. Ensure that the API key is not exposed or stored in plain text. -- **Error Handling and Logging**: Improve error handling mechanisms to provide clearer, more actionable feedback to users. Enhance logging capabilities for debugging and issue resolution, with an option for users to easily report issues. -- **Automatic Updates**: Implement a mechanism for automatically checking and applying updates to the plugin and the models it supports. Ensure that users can easily access the latest features and fixes. +- **Secure API Key Storage**: Enhance the security of API key storage using encryption or integration with secure vaults. Ensure that the API key is not exposed + or stored in plain text. +- **Error Handling and Logging**: Improve error handling mechanisms to provide clearer, more actionable feedback to users. Enhance logging capabilities for + debugging and issue resolution, with an option for users to easily report issues. +- **Automatic Updates**: Implement a mechanism for automatically checking and applying updates to the plugin and the models it supports. Ensure that users can + easily access the latest features and fixes. #### Phase 5: Community and Collaboration -- **Plugin Extension API**: Develop an API that allows other developers to extend and customize the functionality of the plugin. Encourage community contributions by providing clear documentation and examples. -- **Feedback Loop**: Establish a system for collecting user feedback directly through the plugin. Use this feedback to prioritize future development efforts. -- **Collaboration Features**: Introduce features that facilitate collaboration among team members, such as shared action settings, model configurations, and command histories. +- **Plugin Extension API**: Develop an API that allows other developers to extend and customize the functionality of the plugin. Encourage community + contributions by providing clear documentation and examples. +- **Feedback Loop**: Establish a system for collecting user feedback directly through the plugin. Use this feedback to prioritize future development efforts. +- **Collaboration Features**: Introduce features that facilitate collaboration among team members, such as shared action settings, model configurations, and + command histories. #### Conclusion -This roadmap outlines a strategic approach to developing the `AppSettingsState` class and its associated features. By focusing on refinement, feature enhancements, advanced functionality, security, and community collaboration, the project can evolve to meet the needs of its users while fostering a vibrant developer community. -# resources\sources\kt\com\github\simiacryptus\aicoder\config\AppSettingsComponent.kt +This roadmap outlines a strategic approach to developing the `AppSettingsState` class and its associated features. By focusing on refinement, feature +enhancements, advanced functionality, security, and community collaboration, the project can evolve to meet the needs of its users while fostering a vibrant +developer community. -Developing a feature-rich application requires careful planning and execution. Below is a structured roadmap for the development of new features for the AppSettingsComponent, focusing on enhancing user experience, functionality, and performance. +# resources\sources\kt\com\github\simiacryptus\aicoder\config\AppSettingsComponent.kt +Developing a feature-rich application requires careful planning and execution. Below is a structured roadmap for the development of new features for the +AppSettingsComponent, focusing on enhancing user experience, functionality, and performance. #### Phase 1: Initial Setup and Core Functionality - ##### 1.1 User Interface Enhancements + - **Objective:** Improve the usability and aesthetics of the settings component. - **Tasks:** - Implement a more intuitive layout for the settings panel. - Introduce tooltips for each setting to guide users on their purpose and usage. - ##### 1.2 Expand Language Support + - **Objective:** Allow users to select their preferred human language for the application interface. - **Tasks:** - Integrate a language selection dropdown with support for multiple languages. - Implement dynamic language switching without requiring a restart. - ##### 1.3 Listening Port and Endpoint Configuration + - **Objective:** Enable users to customize the listening port and endpoint for better integration with their development environment. - **Tasks:** - Provide input fields for specifying custom port and endpoint. - Validate user input to ensure it meets technical requirements. - #### Phase 2: Advanced Settings and Customization - ##### 2.1 Model Selection Enhancement + - **Objective:** Offer a more comprehensive and user-friendly model selection process. - **Tasks:** - Extend the model selection dropdown to include descriptions and use cases for each model. - Allow users to add custom models by specifying a model URL or uploading a model file. - ##### 2.2 API Log Management + - **Objective:** Improve the management and accessibility of API logs for debugging and analysis. - **Tasks:** - Develop a log viewer within the application for easy access to API logs. - Implement log filtering and search functionality to help users quickly find relevant information. - ##### 2.3 Developer Tools and API Request Editing + - **Objective:** Provide advanced tools for developers to customize and debug API requests. - **Tasks:** - Introduce a request editor with syntax highlighting and validation. - Offer a sandbox environment for testing modified API requests. - #### Phase 3: Performance Optimization and Scalability - ##### 3.1 Optimize Application Performance + - **Objective:** Ensure the application runs smoothly and efficiently, even with extensive usage. - **Tasks:** - Profile the application to identify and address performance bottlenecks. - Optimize data handling and UI rendering for better responsiveness. - ##### 3.2 Scalability Improvements + - **Objective:** Prepare the application for scaling to support a larger number of users and more complex use cases. - **Tasks:** - Implement efficient data storage and retrieval mechanisms. - Ensure the application architecture supports modular enhancements and integrations. - #### Phase 4: Security and Compliance - ##### 4.1 Enhance Security Measures + - **Objective:** Strengthen the application's security to protect user data and API interactions. - **Tasks:** - Introduce encryption for sensitive information, such as API keys. - Conduct security audits and address potential vulnerabilities. - ##### 4.2 Compliance with Standards + - **Objective:** Ensure the application complies with relevant industry standards and regulations. - **Tasks:** - Review and implement necessary changes to meet data protection and privacy regulations. - Document compliance measures and provide users with transparency regarding data usage. - #### Phase 5: User Feedback and Continuous Improvement - ##### 5.1 Collect and Analyze User Feedback + - **Objective:** Gather user feedback to inform future development priorities and improvements. - **Tasks:** - Implement a feedback collection mechanism within the application. - Regularly review feedback and identify common themes or requests. - ##### 5.2 Continuous Feature Development + - **Objective:** Continuously develop and release new features based on user feedback and emerging trends. - **Tasks:** - Establish a roadmap update process to incorporate new ideas and feedback. - Prioritize feature development based on user impact and technical feasibility. -This roadmap outlines a strategic approach to developing the AppSettingsComponent, focusing on delivering value to users through enhanced functionality, performance, and user experience. Regular reviews and adjustments to the roadmap will be necessary to adapt to changing requirements and feedback. +This roadmap outlines a strategic approach to developing the AppSettingsComponent, focusing on delivering value to users through enhanced functionality, +performance, and user experience. Regular reviews and adjustments to the roadmap will be necessary to adapt to changing requirements and feedback. # resources\sources\kt\com\github\simiacryptus\aicoder\config\MRUItems.kt -Creating a feature development roadmap for the `MRUItems` class involves planning the addition of new features, improvements, and optimizations to enhance its functionality, performance, and usability. Below is a proposed roadmap that outlines potential milestones and features to be developed: - +Creating a feature development roadmap for the `MRUItems` class involves planning the addition of new features, improvements, and optimizations to enhance its +functionality, performance, and usability. Below is a proposed roadmap that outlines potential milestones and features to be developed: #### Phase 1: Core Functionality Enhancements -- **Refinement of History Management**: Improve the efficiency of adding, removing, and managing items in both `mostUsedHistory` and `mostRecentHistory`. This could involve optimizing data structures or algorithms used for these operations. -- **Dynamic History Limit Configuration**: Allow users to dynamically adjust the `historyLimit` at runtime, rather than having it fixed. This would provide greater flexibility in managing the size of the history according to the application's needs. +- **Refinement of History Management**: Improve the efficiency of adding, removing, and managing items in both `mostUsedHistory` and `mostRecentHistory`. This + could involve optimizing data structures or algorithms used for these operations. +- **Dynamic History Limit Configuration**: Allow users to dynamically adjust the `historyLimit` at runtime, rather than having it fixed. This would provide + greater flexibility in managing the size of the history according to the application's needs. #### Phase 2: Feature Additions -- **Search Functionality**: Implement a search feature that allows users to query both the most recent and most used histories with partial or complete matches. This would enhance the usability of the class by enabling quick retrieval of specific instructions. -- **Persistence Layer**: Add the ability to persist the history to disk or a database, enabling the history to be retained across application restarts. This could involve serialization/deserialization mechanisms or integration with a database. +- **Search Functionality**: Implement a search feature that allows users to query both the most recent and most used histories with partial or complete matches. + This would enhance the usability of the class by enabling quick retrieval of specific instructions. +- **Persistence Layer**: Add the ability to persist the history to disk or a database, enabling the history to be retained across application restarts. This + could involve serialization/deserialization mechanisms or integration with a database. #### Phase 3: Performance Optimization -- **Memory Usage Optimization**: Analyze and optimize the memory footprint of the `MRUItems` class, ensuring that it remains efficient even with large histories. This might involve using more memory-efficient data structures or implementing memory-saving techniques. -- **Concurrency Improvements**: Enhance the concurrency model to support more efficient multi-threaded access, potentially by using lock-free data structures or optimizing the existing synchronization blocks. +- **Memory Usage Optimization**: Analyze and optimize the memory footprint of the `MRUItems` class, ensuring that it remains efficient even with large + histories. This might involve using more memory-efficient data structures or implementing memory-saving techniques. +- **Concurrency Improvements**: Enhance the concurrency model to support more efficient multi-threaded access, potentially by using lock-free data structures or + optimizing the existing synchronization blocks. #### Phase 4: Usability and Integration -- **API Documentation and Examples**: Provide comprehensive API documentation and example use cases to help developers understand and integrate the `MRUItems` class into their projects more easily. -- **Integration with Other Systems**: Develop plugins or adapters that allow `MRUItems` to be easily integrated with popular frameworks or applications, enhancing its applicability in a wider range of projects. +- **API Documentation and Examples**: Provide comprehensive API documentation and example use cases to help developers understand and integrate the `MRUItems` + class into their projects more easily. +- **Integration with Other Systems**: Develop plugins or adapters that allow `MRUItems` to be easily integrated with popular frameworks or applications, + enhancing its applicability in a wider range of projects. #### Phase 5: Advanced Features -- **Analytics and Reporting**: Implement analytics features that provide insights into the usage patterns of the history, such as the most frequently accessed items over time, trends, and other statistics. -- **Customizable Eviction Policies**: Allow users to define custom policies for evicting items from the history, beyond the most recently used and most frequently used criteria. This could include time-based expiration, priority levels, and more. +- **Analytics and Reporting**: Implement analytics features that provide insights into the usage patterns of the history, such as the most frequently accessed + items over time, trends, and other statistics. +- **Customizable Eviction Policies**: Allow users to define custom policies for evicting items from the history, beyond the most recently used and most + frequently used criteria. This could include time-based expiration, priority levels, and more. #### Phase 6: Community Feedback and Iteration -- **Feedback Loop**: Establish a mechanism for collecting user feedback on the `MRUItems` class, including feature requests, bug reports, and performance issues. -- **Iterative Improvement**: Based on user feedback and usage data, continuously iterate on the `MRUItems` class, adding new features, fixing bugs, and making performance improvements. + +- **Feedback Loop**: Establish a mechanism for collecting user feedback on the `MRUItems` class, including feature requests, bug reports, and performance + issues. +- **Iterative Improvement**: Based on user feedback and usage data, continuously iterate on the `MRUItems` class, adding new features, fixing bugs, and making + performance improvements. This roadmap is a starting point and may evolve based on user needs, technological advancements, and feedback from the developer community. # resources\sources\kt\com\github\simiacryptus\aicoder\config\Name.kt -Creating a feature development roadmap for the `Name` annotation within the `com.github.simiacryptus.aicoder.config` package involves outlining a series of planned enhancements and functionalities that will be added over time. This roadmap will guide the development process, ensuring that the annotation becomes more versatile and useful for its intended purpose. Here's a proposed roadmap: - +Creating a feature development roadmap for the `Name` annotation within the `com.simiacryptus.aicoder.config` package involves outlining a series of planned +enhancements and functionalities that will be added over time. This roadmap will guide the development process, ensuring that the annotation becomes more +versatile and useful for its intended purpose. Here's a proposed roadmap: #### Phase 1: Initial Release + - **Current State**: The `Name` annotation is defined with a single `value` parameter that allows specifying a name for the annotated element. - **Objective**: Ensure the annotation is correctly recognized and utilized in the project. - **Features**: - Implement basic usage of the `Name` annotation in classes, methods, and fields to specify custom names. - Develop documentation and examples demonstrating how to use the `Name` annotation. - #### Phase 2: Integration and Compatibility + - **Objective**: Enhance the annotation to be easily integrated with other tools and frameworks. - **Features**: - Add support for integration with popular serialization libraries (e.g., Jackson, Gson) to use the `Name` value for serialized names. - Ensure compatibility with reflection tools, allowing them to recognize and utilize the `Name` annotation. - #### Phase 3: Advanced Configuration + - **Objective**: Introduce additional parameters to the annotation for more complex configurations. - **Features**: - Add optional parameters to the annotation for specifying naming conventions (e.g., snake_case, camelCase). - Introduce a parameter to toggle the inclusion of the annotated element in certain processes (e.g., serialization, logging). - #### Phase 4: Dynamic Name Generation + - **Objective**: Allow dynamic generation of names based on context or conditions. - **Features**: - Develop a mechanism for specifying name generation strategies, possibly through additional annotations or a companion annotation. - Implement support for conditional naming, where the name can change based on runtime conditions or environment variables. - #### Phase 5: Tooling and Ecosystem + - **Objective**: Create tools and extensions to enhance the usability and adoption of the `Name` annotation. - **Features**: - Develop plugins or extensions for popular IDEs (e.g., IntelliJ IDEA, Eclipse) that provide autocomplete and validation for the `Name` annotation. - - Create a dashboard or utility tool for analyzing and managing all `Name` annotations within a project, offering insights into naming conventions and potential conflicts. - + - Create a dashboard or utility tool for analyzing and managing all `Name` annotations within a project, offering insights into naming conventions and + potential conflicts. #### Phase 6: Community and Feedback + - **Objective**: Establish a feedback loop with the user community to guide future development. - **Features**: - Set up a public repository for the project (if not already done) to gather user feedback and contributions. - Regularly review community suggestions and incorporate feasible enhancements into the roadmap. - #### Phase 7: Continuous Improvement + - **Objective**: Keep the annotation and its ecosystem up-to-date with the latest technology trends and user needs. - **Features**: - Periodically revisit and revise the roadmap based on new technology trends, user feedback, and the evolving landscape of software development. - Explore opportunities for integrating AI and machine learning for more intelligent naming suggestions and conflict resolution. -This roadmap is a living document and should be revisited regularly to adjust the direction and priorities based on new insights, technological advancements, and user feedback. +This roadmap is a living document and should be revisited regularly to adjust the direction and priorities based on new insights, technological advancements, +and user feedback. # resources\sources\kt\com\github\simiacryptus\aicoder\config\SimpleEnvelope.kt -Creating a feature development roadmap for the `SimpleEnvelope` class within the `com.github.simiacryptus.aicoder.config` package involves outlining a series of enhancements and new functionalities that can be added to make the class more robust, versatile, and useful in various applications. Here's a proposed roadmap: - +Creating a feature development roadmap for the `SimpleEnvelope` class within the `com.simiacryptus.aicoder.config` package involves outlining a series of +enhancements and new functionalities that can be added to make the class more robust, versatile, and useful in various applications. Here's a proposed roadmap: #### Phase 1: Basic Enhancements -- **Immutable Value Support**: Introduce a way to make `SimpleEnvelope` immutable after its creation. This could involve adding a boolean flag that, once the value is set, prevents further modifications. -- **Validation**: Implement value validation upon setting it. This could involve a simple non-null check or more complex validations based on predefined criteria. +- **Immutable Value Support**: Introduce a way to make `SimpleEnvelope` immutable after its creation. This could involve adding a boolean flag that, once the + value is set, prevents further modifications. +- **Validation**: Implement value validation upon setting it. This could involve a simple non-null check or more complex validations based on predefined + criteria. #### Phase 2: Functional Extensions -- **Serialization Support**: Add support for serializing and deserializing `SimpleEnvelope` instances, making it easier to store and transmit objects of this class. -- **Listener Mechanism**: Implement a listener mechanism that notifies registered observers when the value changes. This is particularly useful in applications with a GUI or in scenarios where changes need to be tracked. +- **Serialization Support**: Add support for serializing and deserializing `SimpleEnvelope` instances, making it easier to store and transmit objects of this + class. +- **Listener Mechanism**: Implement a listener mechanism that notifies registered observers when the value changes. This is particularly useful in applications + with a GUI or in scenarios where changes need to be tracked. #### Phase 3: Integration and Utility Methods -- **Utility Methods**: Introduce utility methods such as `isEmpty()`, `isPresent()`, and `ifPresent(Consumer consumer)` to make it easier to work with instances of `SimpleEnvelope`. -- **Conversion Methods**: Add methods to convert the `value` to different types, such as `toInt()`, `toDouble()`, etc., with appropriate error handling for invalid conversions. +- **Utility Methods**: Introduce utility methods such as `isEmpty()`, `isPresent()`, and `ifPresent(Consumer consumer)` to make it easier to + work with instances of `SimpleEnvelope`. +- **Conversion Methods**: Add methods to convert the `value` to different types, such as `toInt()`, `toDouble()`, etc., with appropriate error handling for + invalid conversions. #### Phase 4: Advanced Features -- **Encryption/Decryption**: Implement functionality to encrypt and decrypt the `value` stored within `SimpleEnvelope`, making it suitable for handling sensitive information. -- **Versioning**: Add version control for the `value`, allowing users to track changes over time and revert to previous versions if necessary. +- **Encryption/Decryption**: Implement functionality to encrypt and decrypt the `value` stored within `SimpleEnvelope`, making it suitable for handling + sensitive information. +- **Versioning**: Add version control for the `value`, allowing users to track changes over time and revert to previous versions if necessary. #### Phase 5: Interoperability -- **Framework Integration**: Ensure `SimpleEnvelope` can easily integrate with popular frameworks such as Spring, Hibernate, or Jakarta EE. This might involve creating custom annotations or adapters. -- **Language Support**: Explore the possibility of making `SimpleEnvelope` usable from other JVM languages such as Kotlin and Scala, potentially leveraging their unique features for added functionality. +- **Framework Integration**: Ensure `SimpleEnvelope` can easily integrate with popular frameworks such as Spring, Hibernate, or Jakarta EE. This might involve + creating custom annotations or adapters. +- **Language Support**: Explore the possibility of making `SimpleEnvelope` usable from other JVM languages such as Kotlin and Scala, potentially leveraging + their unique features for added functionality. #### Phase 6: Performance and Scalability -- **Benchmarking**: Conduct comprehensive benchmark tests to identify performance bottlenecks and optimize them. -- **Scalability Enhancements**: Investigate and implement improvements to ensure `SimpleEnvelope` performs well in high-concurrency environments and large-scale applications. +- **Benchmarking**: Conduct comprehensive benchmark tests to identify performance bottlenecks and optimize them. +- **Scalability Enhancements**: Investigate and implement improvements to ensure `SimpleEnvelope` performs well in high-concurrency environments and large-scale + applications. #### Phase 7: Documentation and Community -- **Comprehensive Documentation**: Develop detailed documentation covering all aspects of `SimpleEnvelope`, including code examples, use cases, and integration guides. -- **Community Engagement**: Establish a community around `SimpleEnvelope` for users to share experiences, use cases, and custom extensions, fostering an ecosystem around the class. -This roadmap provides a structured approach to developing the `SimpleEnvelope` class, gradually enhancing its functionality, usability, and integration capabilities. Each phase builds upon the previous ones, ensuring a solid foundation is in place before adding more complex features. +- **Comprehensive Documentation**: Develop detailed documentation covering all aspects of `SimpleEnvelope`, including code examples, use cases, and integration + guides. +- **Community Engagement**: Establish a community around `SimpleEnvelope` for users to share experiences, use cases, and custom extensions, fostering an + ecosystem around the class. -# resources\sources\kt\com\github\simiacryptus\aicoder\config\NonReflectionAppSettingsConfigurable.kt +This roadmap provides a structured approach to developing the `SimpleEnvelope` class, gradually enhancing its functionality, usability, and integration +capabilities. Each phase builds upon the previous ones, ensuring a solid foundation is in place before adding more complex features. -Creating a feature development roadmap for the `NonReflectionAppSettingsConfigurable` class and its associated functionalities involves outlining a series of enhancements, new features, and improvements that can be made to enrich the user experience, increase performance, and ensure the robustness of the application settings configuration. Here's a proposed roadmap: +# resources\sources\kt\com\github\simiacryptus\aicoder\config\NonReflectionAppSettingsConfigurable.kt +Creating a feature development roadmap for the `NonReflectionAppSettingsConfigurable` class and its associated functionalities involves outlining a series of +enhancements, new features, and improvements that can be made to enrich the user experience, increase performance, and ensure the robustness of the application +settings configuration. Here's a proposed roadmap: #### Phase 1: Usability Enhancements -- **UI Improvements**: Refine the user interface for configuring app settings to make it more intuitive and user-friendly. This includes better grouping of related settings, tooltips for information, and a responsive design for different window sizes. -- **Validation and Feedback**: Implement real-time validation for input fields with immediate user feedback to prevent configuration errors. For example, ensuring valid numerical inputs for ports and implementing regex validation for text fields where applicable. +- **UI Improvements**: Refine the user interface for configuring app settings to make it more intuitive and user-friendly. This includes better grouping of + related settings, tooltips for information, and a responsive design for different window sizes. +- **Validation and Feedback**: Implement real-time validation for input fields with immediate user feedback to prevent configuration errors. For example, + ensuring valid numerical inputs for ports and implementing regex validation for text fields where applicable. #### Phase 2: Performance Optimization -- **Lazy Loading**: Optimize the settings UI to load tabs and components lazily. This means only loading the UI components of a tab when the tab is accessed, reducing the initial load time. -- **Efficient Logging**: Improve the logging mechanism to be more efficient, possibly by introducing log levels and asynchronous logging to avoid UI freezes during file operations. +- **Lazy Loading**: Optimize the settings UI to load tabs and components lazily. This means only loading the UI components of a tab when the tab is accessed, + reducing the initial load time. +- **Efficient Logging**: Improve the logging mechanism to be more efficient, possibly by introducing log levels and asynchronous logging to avoid UI freezes + during file operations. #### Phase 3: Security Enhancements -- **Secure API Key Storage**: Implement a more secure way to store and handle API keys within the application, such as encryption at rest. -- **Input Sanitization**: Ensure all user inputs are sanitized to prevent injection attacks, especially for fields that might be used in network requests or command-line operations. +- **Secure API Key Storage**: Implement a more secure way to store and handle API keys within the application, such as encryption at rest. +- **Input Sanitization**: Ensure all user inputs are sanitized to prevent injection attacks, especially for fields that might be used in network requests or + command-line operations. #### Phase 4: Advanced Features -- **Customizable Themes**: Introduce theme support for the settings UI, allowing users to customize the look and feel according to their preferences. -- **Profile Management**: Allow users to create and switch between multiple configuration profiles, enabling easy transitions between different setups for various projects or environments. +- **Customizable Themes**: Introduce theme support for the settings UI, allowing users to customize the look and feel according to their preferences. +- **Profile Management**: Allow users to create and switch between multiple configuration profiles, enabling easy transitions between different setups for + various projects or environments. #### Phase 5: Integration and Extensibility -- **Plugin System**: Develop a plugin system that allows third-party developers to extend the functionality of the settings configurator with custom tabs, settings, and validators. -- **API Exposure**: Expose a set of APIs for programmatic access to the settings, enabling automation scripts and external tools to read from or write to the application settings programmatically. +- **Plugin System**: Develop a plugin system that allows third-party developers to extend the functionality of the settings configurator with custom tabs, + settings, and validators. +- **API Exposure**: Expose a set of APIs for programmatic access to the settings, enabling automation scripts and external tools to read from or write to the + application settings programmatically. #### Phase 6: Testing and Documentation -- **Comprehensive Testing**: Implement a comprehensive suite of automated tests, including unit tests, integration tests, and UI tests, to ensure the reliability and stability of the settings configurator. -- **Documentation**: Create detailed documentation covering all aspects of the settings configurator, including user guides, API documentation, and developer guides for extending functionality. +- **Comprehensive Testing**: Implement a comprehensive suite of automated tests, including unit tests, integration tests, and UI tests, to ensure the + reliability and stability of the settings configurator. +- **Documentation**: Create detailed documentation covering all aspects of the settings configurator, including user guides, API documentation, and developer + guides for extending functionality. #### Phase 7: Community Feedback and Iteration -- **Feedback Loop**: Establish a feedback loop with the user community to gather insights, suggestions, and reports on issues. Use this feedback to prioritize future developments and improvements. -- **Iterative Improvements**: Based on community feedback and usage analytics, continuously iterate on features, usability, and performance to meet the evolving needs of the users. -This roadmap provides a structured approach to developing the `NonReflectionAppSettingsConfigurable` class and its related components, focusing on delivering value to users while ensuring the application remains scalable, secure, and maintainable. +- **Feedback Loop**: Establish a feedback loop with the user community to gather insights, suggestions, and reports on issues. Use this feedback to prioritize + future developments and improvements. +- **Iterative Improvements**: Based on community feedback and usage analytics, continuously iterate on features, usability, and performance to meet the evolving + needs of the users. -# resources\sources\kt\com\github\simiacryptus\aicoder\config\StaticAppSettingsConfigurable.kt +This roadmap provides a structured approach to developing the `NonReflectionAppSettingsConfigurable` class and its related components, focusing on delivering +value to users while ensuring the application remains scalable, secure, and maintainable. -Creating a feature development roadmap for the `StaticAppSettingsConfigurable` class and its associated functionalities involves outlining the future enhancements, bug fixes, and new features that could be implemented to improve the user experience, performance, and capabilities of the application settings configuration within a plugin environment. Here's a proposed roadmap: +# resources\sources\kt\com\github\simiacryptus\aicoder\config\StaticAppSettingsConfigurable.kt +Creating a feature development roadmap for the `StaticAppSettingsConfigurable` class and its associated functionalities involves outlining the future +enhancements, bug fixes, and new features that could be implemented to improve the user experience, performance, and capabilities of the application settings +configuration within a plugin environment. Here's a proposed roadmap: #### Phase 1: Usability Enhancements -- **UI Improvements**: Refine the user interface for configuring application settings to make it more intuitive and user-friendly. This could include better grouping of related settings, tooltips for information, and a more visually appealing layout. -- **Validation and Feedback**: Implement real-time validation for input fields with immediate user feedback to prevent configuration errors. For example, verifying API keys or port numbers as they are entered. -- **Search Functionality**: Add a search feature within the settings panel to allow users to quickly find specific settings. +- **UI Improvements**: Refine the user interface for configuring application settings to make it more intuitive and user-friendly. This could include better + grouping of related settings, tooltips for information, and a more visually appealing layout. +- **Validation and Feedback**: Implement real-time validation for input fields with immediate user feedback to prevent configuration errors. For example, + verifying API keys or port numbers as they are entered. +- **Search Functionality**: Add a search feature within the settings panel to allow users to quickly find specific settings. #### Phase 2: Performance and Efficiency + - **Lazy Loading**: Optimize the settings UI to load sections lazily as they are accessed, improving the initial load time and performance. - **Caching Mechanism**: Implement a caching mechanism for settings that require loading external data, reducing wait times for the user. - **Background Processing**: Move intensive processing tasks to background threads to keep the UI responsive. - #### Phase 3: Security Enhancements + - **Secure Storage**: Ensure sensitive information, such as API keys, is stored securely using encryption. - **Access Control**: Add configurable access control for different levels of settings, allowing administrators to restrict access to critical settings. - #### Phase 4: Advanced Features + - **Customizable Themes**: Introduce theme support for the settings UI, allowing users to customize the appearance according to their preferences. -- **Profile Management**: Allow users to create, export, and import profiles with predefined settings, facilitating easier setup on new installations or different environments. +- **Profile Management**: Allow users to create, export, and import profiles with predefined settings, facilitating easier setup on new installations or + different environments. - **API Log Filtering**: Enhance the API log functionality with filtering capabilities, enabling users to focus on specific events or errors. - #### Phase 5: Integration and Extensibility -- **Plugin API**: Develop an API that allows other plugins to integrate with and extend the settings, promoting a more cohesive ecosystem. -- **External Configuration Sources**: Add support for loading settings from external sources, such as environment variables or configuration files, enabling more flexible deployment scenarios. +- **Plugin API**: Develop an API that allows other plugins to integrate with and extend the settings, promoting a more cohesive ecosystem. +- **External Configuration Sources**: Add support for loading settings from external sources, such as environment variables or configuration files, enabling + more flexible deployment scenarios. #### Phase 6: Documentation and Support -- **Comprehensive Documentation**: Create detailed documentation covering all aspects of the settings configuration, including examples and best practices. -- **Community Forum**: Establish a community forum or support channel where users can share tips, ask questions, and provide feedback on the settings functionality. +- **Comprehensive Documentation**: Create detailed documentation covering all aspects of the settings configuration, including examples and best practices. +- **Community Forum**: Establish a community forum or support channel where users can share tips, ask questions, and provide feedback on the settings + functionality. #### Phase 7: Continuous Improvement + - **User Feedback Loop**: Implement a mechanism for collecting user feedback directly through the settings UI, guiding future development priorities. -- **Automated Testing**: Enhance the robustness of the settings functionality with a comprehensive suite of automated tests, including unit, integration, and UI tests. +- **Automated Testing**: Enhance the robustness of the settings functionality with a comprehensive suite of automated tests, including unit, integration, and UI + tests. -This roadmap is designed to be iterative, allowing for adjustments and additions based on user feedback and technological advancements. Each phase builds upon the previous ones, gradually enhancing the functionality, usability, and performance of the application settings configuration. +This roadmap is designed to be iterative, allowing for adjustments and additions based on user feedback and technological advancements. Each phase builds upon +the previous ones, gradually enhancing the functionality, usability, and performance of the application settings configuration. # resources\sources\kt\com\github\simiacryptus\aicoder\config\UsageTable.kt -Creating a feature development roadmap for the `UsageTable` class involves outlining the planned enhancements, improvements, and new functionalities that could be added to make it more robust, user-friendly, and feature-rich. Below is a proposed roadmap that outlines potential features and improvements, categorized into short-term, mid-term, and long-term goals. - +Creating a feature development roadmap for the `UsageTable` class involves outlining the planned enhancements, improvements, and new functionalities that could +be added to make it more robust, user-friendly, and feature-rich. Below is a proposed roadmap that outlines potential features and improvements, categorized +into short-term, mid-term, and long-term goals. #### Short-Term Goals (1-3 Months) + - **Performance Optimization:** Implement lazy loading for the table data to improve performance when dealing with large datasets. -- **User Interface Enhancements:** Improve the visual appeal of the table and buttons, possibly by integrating with the IntelliJ Platform's theme system for a more seamless look and feel. +- **User Interface Enhancements:** Improve the visual appeal of the table and buttons, possibly by integrating with the IntelliJ Platform's theme system for a + more seamless look and feel. - **Column Sorting:** Enable sorting for each column, allowing users to easily organize the data according to their preferences. - #### Mid-Term Goals (4-6 Months) + - **Filtering Capabilities:** Add a filtering option that allows users to filter the table data based on specific criteria (e.g., model name, cost range). - **Export Functionality:** Implement the ability to export the table data to common formats such as CSV, JSON, or Excel for further analysis or reporting. - **User Preferences:** Allow users to customize the table view, such as choosing which columns to display, and save these preferences for future sessions. - #### Long-Term Goals (7-12 Months) -- **Integration with Other Tools:** Explore the possibility of integrating the `UsageTable` with other tools and services, such as billing systems or project management tools, to provide a more comprehensive usage overview. -- **Advanced Analytics:** Incorporate analytics features that can provide insights into usage patterns, cost trends, and predictive analysis for budgeting purposes. -- **Accessibility Improvements:** Ensure that the `UsageTable` is accessible, following best practices and guidelines for accessibility to make it usable for all users, including those with disabilities. +- **Integration with Other Tools:** Explore the possibility of integrating the `UsageTable` with other tools and services, such as billing systems or project + management tools, to provide a more comprehensive usage overview. +- **Advanced Analytics:** Incorporate analytics features that can provide insights into usage patterns, cost trends, and predictive analysis for budgeting + purposes. +- **Accessibility Improvements:** Ensure that the `UsageTable` is accessible, following best practices and guidelines for accessibility to make it usable for + all users, including those with disabilities. #### Continuous Improvements -- **Feedback Loop:** Establish a mechanism for collecting user feedback and incorporating it into the development process to ensure that the tool evolves in a direction that meets the users' needs. -- **Documentation and Tutorials:** Continuously update the documentation and provide tutorials to help new users get started and enable advanced users to make the most out of the tool's features. + +- **Feedback Loop:** Establish a mechanism for collecting user feedback and incorporating it into the development process to ensure that the tool evolves in a + direction that meets the users' needs. +- **Documentation and Tutorials:** Continuously update the documentation and provide tutorials to help new users get started and enable advanced users to make + the most out of the tool's features. - **Security and Privacy:** Regularly review and enhance the security and privacy measures to protect user data and ensure compliance with relevant regulations. -This roadmap is a living document and should be revisited and revised based on user feedback, technological advancements, and changes in the project's goals and priorities. +This roadmap is a living document and should be revisited and revised based on user feedback, technological advancements, and changes in the project's goals and +priorities. # resources\sources\kt\com\github\simiacryptus\aicoder\ui\EditorMenu.kt -Developing a feature for a software project, especially one that integrates with complex platforms like IntelliJ IDEA (as suggested by the provided code snippet), requires careful planning and execution. Below is a structured roadmap to guide the development of a new feature for the `com.github.simiacryptus.aicoder.ui` package, focusing on enhancing the editor menu with additional actions based on user settings. - +Developing a feature for a software project, especially one that integrates with complex platforms like IntelliJ IDEA (as suggested by the provided code +snippet), requires careful planning and execution. Below is a structured roadmap to guide the development of a new feature for the `com.simiacryptus.aicoder.ui` +package, focusing on enhancing the editor menu with additional actions based on user settings. #### Phase 1: Requirements Gathering and Analysis -1. **Identify Stakeholder Needs:** Engage with users and stakeholders to understand what enhancements they need in the editor menu. This could involve surveys, interviews, or reviewing feedback from existing tools. - -2. **Define Feature Scope:** Based on the feedback, clearly define what the new feature will and will not include. This might involve adding new actions to the editor menu, customizing existing actions, or providing a dynamic menu based on the context. +1. **Identify Stakeholder Needs:** Engage with users and stakeholders to understand what enhancements they need in the editor menu. This could involve surveys, + interviews, or reviewing feedback from existing tools. -3. **Analyze Technical Feasibility:** Review the IntelliJ IDEA plugin development documentation and the current project structure to understand the technical requirements and constraints. +2. **Define Feature Scope:** Based on the feedback, clearly define what the new feature will and will not include. This might involve adding new actions to the + editor menu, customizing existing actions, or providing a dynamic menu based on the context. +3. **Analyze Technical Feasibility:** Review the IntelliJ IDEA plugin development documentation and the current project structure to understand the technical + requirements and constraints. #### Phase 2: Design -4. **Create a Feature Specification Document:** Detail the technical specifications, including how the feature will interact with the IntelliJ platform and any external dependencies. +4. **Create a Feature Specification Document:** Detail the technical specifications, including how the feature will interact with the IntelliJ platform and any + external dependencies. -5. **Design User Interface:** If the feature involves UI changes, mock up how these will look and feel. For the editor menu enhancements, this could involve designing the layout of new actions or how users can customize the menu. - -6. **Architecture Planning:** Plan how the feature will be integrated into the existing codebase, considering aspects like maintainability, scalability, and performance. +5. **Design User Interface:** If the feature involves UI changes, mock up how these will look and feel. For the editor menu enhancements, this could involve + designing the layout of new actions or how users can customize the menu. +6. **Architecture Planning:** Plan how the feature will be integrated into the existing codebase, considering aspects like maintainability, scalability, and + performance. #### Phase 3: Implementation -7. **Setup Development Environment:** Ensure all developers have the necessary tools and access, including IntelliJ IDEA, JDK, and any required plugins or libraries. - -8. **Develop Feature:** Start coding the feature based on the design documents and specifications. For the `EditorMenu` class, this involves implementing the logic to dynamically add or modify actions based on user settings. +7. **Setup Development Environment:** Ensure all developers have the necessary tools and access, including IntelliJ IDEA, JDK, and any required plugins or + libraries. -9. **Code Review and Quality Assurance:** Conduct regular code reviews and apply static code analysis tools to ensure code quality. Implement unit and integration tests to cover new functionality. +8. **Develop Feature:** Start coding the feature based on the design documents and specifications. For the `EditorMenu` class, this involves implementing the + logic to dynamically add or modify actions based on user settings. +9. **Code Review and Quality Assurance:** Conduct regular code reviews and apply static code analysis tools to ensure code quality. Implement unit and + integration tests to cover new functionality. #### Phase 4: Testing -10. **User Acceptance Testing (UAT):** Engage a group of end-users to test the new feature in a controlled environment. Collect feedback and make any necessary adjustments. - -11. **Performance Testing:** Ensure that the new feature does not negatively impact the performance of the IntelliJ IDEA plugin, especially when loading or refreshing the editor menu. +10. **User Acceptance Testing (UAT):** Engage a group of end-users to test the new feature in a controlled environment. Collect feedback and make any necessary + adjustments. +11. **Performance Testing:** Ensure that the new feature does not negatively impact the performance of the IntelliJ IDEA plugin, especially when loading or + refreshing the editor menu. #### Phase 5: Deployment @@ -5169,106 +6347,144 @@ Developing a feature for a software project, especially one that integrates with 14. **Monitor and Support:** After release, monitor the feature for any issues and provide support to users. Collect feedback for future improvements. - #### Phase 6: Review and Iterate 15. **Post-Implementation Review:** Conduct a review of the development process and the feature itself. Identify what went well and what could be improved. 16. **Plan Future Enhancements:** Based on user feedback and the post-implementation review, plan any necessary enhancements or new features. -This roadmap provides a structured approach to developing a new feature, ensuring that user needs are met while maintaining high standards of code quality and performance. +This roadmap provides a structured approach to developing a new feature, ensuring that user needs are met while maintaining high standards of code quality and +performance. # resources\sources\kt\com\github\simiacryptus\aicoder\ui\ProjectMenu.kt -Creating a feature development roadmap for the `ProjectMenu` class within the context of an IntelliJ plugin involves planning out the enhancements, fixes, and new capabilities that you intend to introduce to this component over time. Below is a suggested roadmap that outlines potential directions for the development of the `ProjectMenu` class, taking into consideration its current functionality of customizing the project menu actions based on the application settings. - +Creating a feature development roadmap for the `ProjectMenu` class within the context of an IntelliJ plugin involves planning out the enhancements, fixes, and +new capabilities that you intend to introduce to this component over time. Below is a suggested roadmap that outlines potential directions for the development +of the `ProjectMenu` class, taking into consideration its current functionality of customizing the project menu actions based on the application settings. #### Phase 1: Initial Enhancements and Fixes -- **Refactor and Clean Up**: Begin by refactoring the existing code for clarity and efficiency. Ensure that the code follows best practices and is well-documented. -- **Improve Error Handling**: Enhance error handling within the `getChildren` method to gracefully manage unexpected situations, such as null `AnActionEvent` instances or issues accessing the `AppSettingsState`. -- **Add Logging**: Introduce logging to help with debugging and tracking the behavior of the `ProjectMenu` actions. +- **Refactor and Clean Up**: Begin by refactoring the existing code for clarity and efficiency. Ensure that the code follows best practices and is + well-documented. +- **Improve Error Handling**: Enhance error handling within the `getChildren` method to gracefully manage unexpected situations, such as null `AnActionEvent` + instances or issues accessing the `AppSettingsState`. +- **Add Logging**: Introduce logging to help with debugging and tracking the behavior of the `ProjectMenu` actions. #### Phase 2: User Customization Features -- **UI for Action Configuration**: Develop a user interface within the plugin settings that allows users to customize which actions appear in the project menu. This could involve enabling/disabling specific actions or reordering them. -- **Dynamic Action Loading**: Implement functionality to dynamically load actions based on certain project conditions or user-defined criteria, enhancing the flexibility of the project menu. +- **UI for Action Configuration**: Develop a user interface within the plugin settings that allows users to customize which actions appear in the project menu. + This could involve enabling/disabling specific actions or reordering them. +- **Dynamic Action Loading**: Implement functionality to dynamically load actions based on certain project conditions or user-defined criteria, enhancing the + flexibility of the project menu. #### Phase 3: Integration and Expansion -- **Context-Sensitive Actions**: Enhance the project menu to include actions that are sensitive to the current context or selection within the IDE, such as specific file types or project structures. -- **External Tool Integration**: Allow for the integration of external tools or scripts into the project menu, enabling users to execute custom scripts or tools directly from the menu. +- **Context-Sensitive Actions**: Enhance the project menu to include actions that are sensitive to the current context or selection within the IDE, such as + specific file types or project structures. +- **External Tool Integration**: Allow for the integration of external tools or scripts into the project menu, enabling users to execute custom scripts or tools + directly from the menu. #### Phase 4: Performance and Scalability -- **Performance Optimization**: Analyze and optimize the performance of the project menu, ensuring that the dynamic loading and execution of actions do not negatively impact the IDE's performance. -- **Scalability Enhancements**: Ensure that the project menu can handle a large number of actions efficiently, including providing mechanisms for organizing or grouping actions to maintain usability. +- **Performance Optimization**: Analyze and optimize the performance of the project menu, ensuring that the dynamic loading and execution of actions do not + negatively impact the IDE's performance. +- **Scalability Enhancements**: Ensure that the project menu can handle a large number of actions efficiently, including providing mechanisms for organizing or + grouping actions to maintain usability. #### Phase 5: Feedback Loop and Continuous Improvement -- **User Feedback Collection**: Implement mechanisms to collect user feedback specifically about the project menu, such as usability surveys or usage analytics. -- **Continuous Refinement**: Based on user feedback and observed usage patterns, continuously refine and enhance the project menu features, usability, and performance. +- **User Feedback Collection**: Implement mechanisms to collect user feedback specifically about the project menu, such as usability surveys or usage analytics. +- **Continuous Refinement**: Based on user feedback and observed usage patterns, continuously refine and enhance the project menu features, usability, and + performance. #### Phase 6: Advanced Features + - **Machine Learning Integration**: Explore the integration of machine learning to predict and suggest actions based on the user's habits and project context. -- **Collaborative Features**: Consider adding features that allow teams to share custom actions or configurations, facilitating collaboration and consistency across development environments. +- **Collaborative Features**: Consider adding features that allow teams to share custom actions or configurations, facilitating collaboration and consistency + across development environments. -This roadmap is a starting point and should be adapted based on user feedback, technological advancements, and the specific goals of your plugin development project. +This roadmap is a starting point and should be adapted based on user feedback, technological advancements, and the specific goals of your plugin development +project. # resources\sources\kt\com\github\simiacryptus\aicoder\config\UIAdapter.kt -The `UIAdapter` class serves as a foundational component for managing user interface (UI) settings in an IntelliJ plugin, specifically designed for the hypothetical "AICoder" plugin. This class abstracts the common functionalities needed for creating, displaying, and managing UI components and their associated settings. To further develop and enhance this class and its functionalities, a feature development roadmap is proposed below. This roadmap outlines a series of improvements and new features aimed at increasing usability, flexibility, and efficiency. - +The `UIAdapter` class serves as a foundational component for managing user interface (UI) settings in an IntelliJ plugin, specifically designed for the +hypothetical "AICoder" plugin. This class abstracts the common functionalities needed for creating, displaying, and managing UI components and their associated +settings. To further develop and enhance this class and its functionalities, a feature development roadmap is proposed below. This roadmap outlines a series of +improvements and new features aimed at increasing usability, flexibility, and efficiency. #### Phase 1: Core Improvements + 1. **UI Responsiveness Enhancements** - - Optimize UI rendering and update mechanisms to ensure smooth user interactions, especially for complex settings. + +- Optimize UI rendering and update mechanisms to ensure smooth user interactions, especially for complex settings. + 2. **Dynamic UI Components** - - Implement support for dynamically adding or removing components based on certain conditions or user actions. +- Implement support for dynamically adding or removing components based on certain conditions or user actions. #### Phase 2: Usability Enhancements + 3. **User Feedback Mechanisms** - - Integrate user feedback options directly within the UI settings panel, allowing users to report issues or suggest improvements. + +- Integrate user feedback options directly within the UI settings panel, allowing users to report issues or suggest improvements. + 4. **Search and Filter Capabilities** - - Add search and filter functionalities to allow users to easily find specific settings. +- Add search and filter functionalities to allow users to easily find specific settings. #### Phase 3: Advanced Configuration + 5. **Customizable UI Themes** - - Allow users to customize the appearance of the settings UI, including themes and color schemes. + +- Allow users to customize the appearance of the settings UI, including themes and color schemes. + 6. **Profile Management** - - Enable users to create, save, and switch between multiple settings profiles for different workflows or projects. +- Enable users to create, save, and switch between multiple settings profiles for different workflows or projects. #### Phase 4: Integration and Expansion + 7. **External Configuration Import/Export** - - Develop features for importing and exporting settings from external sources, facilitating easy sharing and backup. + +- Develop features for importing and exporting settings from external sources, facilitating easy sharing and backup. + 8. **Plugin Ecosystem Support** - - Create an API or framework that allows other plugin developers to easily integrate their settings UI with the AICoder settings panel. +- Create an API or framework that allows other plugin developers to easily integrate their settings UI with the AICoder settings panel. #### Phase 5: Performance and Security + 9. **Performance Optimization** - - Continuously monitor and optimize the performance of the settings UI, ensuring it remains fast and responsive as new features are added. + +- Continuously monitor and optimize the performance of the settings UI, ensuring it remains fast and responsive as new features are added. + 10. **Security Enhancements** - - Implement security measures to protect user settings, especially when importing or exporting configurations. +- Implement security measures to protect user settings, especially when importing or exporting configurations. #### Phase 6: Documentation and Community Engagement + 11. **Comprehensive Documentation** - - Provide detailed documentation covering all aspects of the UIAdapter class and its usage, including examples and best practices. + +- Provide detailed documentation covering all aspects of the UIAdapter class and its usage, including examples and best practices. + 12. **Community Feedback Loop** - - Establish a system for gathering and incorporating community feedback into the development roadmap, ensuring the tool evolves in line with user needs. -This roadmap is designed to be iterative, with each phase building upon the successes and lessons learned from the previous ones. By following this roadmap, the AICoder plugin can significantly enhance its UI settings management capabilities, providing a more robust, user-friendly, and flexible tool for developers. +- Establish a system for gathering and incorporating community feedback into the development roadmap, ensuring the tool evolves in line with user needs. -# resources\sources\kt\com\github\simiacryptus\aicoder\ui\ModelSelectionWidgetFactory.kt +This roadmap is designed to be iterative, with each phase building upon the successes and lessons learned from the previous ones. By following this roadmap, the +AICoder plugin can significantly enhance its UI settings management capabilities, providing a more robust, user-friendly, and flexible tool for developers. -The code provided outlines a `ModelSelectionWidgetFactory` class that integrates a model selection widget into the IntelliJ IDE's status bar, allowing users to select and switch between different AI models (e.g., GPT-4, GPT-4 Turbo, GPT-3.5 Turbo) for their development needs. This widget is part of a larger project aimed at enhancing AI-assisted coding capabilities within the IDE. Below is a proposed feature development roadmap to expand on this foundation, focusing on enhancing usability, functionality, and integration. +# resources\sources\kt\com\github\simiacryptus\aicoder\ui\ModelSelectionWidgetFactory.kt +The code provided outlines a `ModelSelectionWidgetFactory` class that integrates a model selection widget into the IntelliJ IDE's status bar, allowing users to +select and switch between different AI models (e.g., GPT-4, GPT-4 Turbo, GPT-3.5 Turbo) for their development needs. This widget is part of a larger project +aimed at enhancing AI-assisted coding capabilities within the IDE. Below is a proposed feature development roadmap to expand on this foundation, focusing on +enhancing usability, functionality, and integration. #### Phase 1: Core Functionality and Usability Enhancements + - **1.1 Model Selection Widget Improvements** - Add search functionality to the model selection popup to quickly filter and select models. - Implement model categorization (e.g., by performance, cost) for easier navigation. @@ -5282,8 +6498,8 @@ The code provided outlines a `ModelSelectionWidgetFactory` class that integrates - Optimize the widget's performance to ensure minimal impact on the IDE's responsiveness. - Implement lazy loading for model information to speed up the initial loading time. - #### Phase 2: Advanced Features and Integration + - **2.1 Model Insights and Analytics** - Integrate a feature to display detailed information about each model, including performance metrics, cost, and usage guidelines. - Provide real-time analytics on the user's model usage, including session summaries and suggestions for cost optimization. @@ -5296,22 +6512,24 @@ The code provided outlines a `ModelSelectionWidgetFactory` class that integrates - Implement functionality for users to share their custom model configurations and preferences with team members. - Develop a community-driven model recommendation system where users can rate and review models based on their experiences. - #### Phase 3: Ecosystem Expansion and External Integrations + - **3.1 External Tools and Services Integration** - Enable integration with external AI services and tools, allowing users to leverage a broader range of models and utilities directly from the IDE. - Implement a plugin API for third-party developers to contribute additional models and integrations. - **3.2 Cross-Platform Support** - - Expand the widget's compatibility to support other IDEs and code editors, enabling a unified AI-assisted coding experience across different development environments. + - Expand the widget's compatibility to support other IDEs and code editors, enabling a unified AI-assisted coding experience across different development + environments. - Develop a cloud synchronization feature for users to maintain consistent settings and preferences across devices and platforms. - **3.3 Advanced Customization and Scripting** - - Introduce support for scripting and macros within the model selection and code suggestion processes, allowing users to automate repetitive tasks and customize the AI's behavior. + - Introduce support for scripting and macros within the model selection and code suggestion processes, allowing users to automate repetitive tasks and + customize the AI's behavior. - Develop a visual editor for creating and editing these scripts, making the feature accessible to users without a programming background. - #### Phase 4: Security, Privacy, and Compliance + - **4.1 Security and Privacy Enhancements** - Implement robust security measures to protect user data and model configurations, including encryption and secure API communication. - Develop a privacy framework ensuring that user data and coding habits are not inadvertently exposed or shared. @@ -5320,81 +6538,93 @@ The code provided outlines a `ModelSelectionWidgetFactory` class that integrates - Ensure the plugin and its features comply with relevant legal and regulatory requirements, including GDPR and CCPA. - Improve accessibility features to ensure the plugin is usable by developers with disabilities. -This roadmap outlines a comprehensive strategy for developing a feature-rich, user-friendly, and versatile AI-assisted coding plugin for IntelliJ and potentially other IDEs. Each phase builds upon the last, gradually expanding the plugin's capabilities and its value to the developer community. +This roadmap outlines a comprehensive strategy for developing a feature-rich, user-friendly, and versatile AI-assisted coding plugin for IntelliJ and +potentially other IDEs. Each phase builds upon the last, gradually expanding the plugin's capabilities and its value to the developer community. # resources\sources\kt\com\github\simiacryptus\aicoder\ui\TemperatureControlWidgetFactory.kt -Creating a feature development roadmap for the `TemperatureControlWidgetFactory` and its associated components involves outlining the future enhancements, improvements, and additions planned for this IntelliJ IDEA plugin. The roadmap will be divided into short-term, mid-term, and long-term goals, focusing on enhancing user experience, functionality, and integration capabilities. - +Creating a feature development roadmap for the `TemperatureControlWidgetFactory` and its associated components involves outlining the future enhancements, +improvements, and additions planned for this IntelliJ IDEA plugin. The roadmap will be divided into short-term, mid-term, and long-term goals, focusing on +enhancing user experience, functionality, and integration capabilities. #### Short-Term Goals (0-3 Months) 1. **Bug Fixes and Stability Improvements:** - - Address any reported bugs related to the temperature slider or the feedback links. - - Ensure compatibility with the latest IntelliJ IDEA versions. + +- Address any reported bugs related to the temperature slider or the feedback links. +- Ensure compatibility with the latest IntelliJ IDEA versions. 2. **UI/UX Enhancements:** - - Improve the visual design of the temperature slider for better readability and accessibility. - - Add tooltips to provide users with more context about the temperature control and feedback options. + +- Improve the visual design of the temperature slider for better readability and accessibility. +- Add tooltips to provide users with more context about the temperature control and feedback options. 3. **Performance Optimization:** - - Optimize the widget's performance to ensure it does not impact the IDE's startup time or overall responsiveness. +- Optimize the widget's performance to ensure it does not impact the IDE's startup time or overall responsiveness. #### Mid-Term Goals (4-6 Months) 1. **Configuration Options:** - - Allow users to configure the temperature range and default value via the plugin settings. - - Provide options to customize the appearance of the widget in the status bar. + +- Allow users to configure the temperature range and default value via the plugin settings. +- Provide options to customize the appearance of the widget in the status bar. 2. **Advanced Temperature Control Features:** - - Introduce a logarithmic scale option for the temperature slider for finer control at lower temperatures. - - Implement a feature to remember the last set temperature across IDE restarts. + +- Introduce a logarithmic scale option for the temperature slider for finer control at lower temperatures. +- Implement a feature to remember the last set temperature across IDE restarts. 3. **Feedback Mechanism Enhancement:** - - Add a feature to allow users to submit feedback directly from the IDE, including feature requests and bug reports. - - Integrate a system to notify users about the status of their submitted feedback. +- Add a feature to allow users to submit feedback directly from the IDE, including feature requests and bug reports. +- Integrate a system to notify users about the status of their submitted feedback. #### Long-Term Goals (7-12 Months) 1. **Integration with AI Services:** - - Explore the possibility of integrating with external AI coding assistants and services to adjust their behavior based on the temperature setting. - - Implement security measures to safely handle API keys and user data. + +- Explore the possibility of integrating with external AI coding assistants and services to adjust their behavior based on the temperature setting. +- Implement security measures to safely handle API keys and user data. 2. **Community and Collaboration Features:** - - Develop a community-driven platform within the plugin for users to share their temperature presets for different programming tasks and languages. - - Allow users to rate and comment on shared presets, fostering a collaborative environment. + +- Develop a community-driven platform within the plugin for users to share their temperature presets for different programming tasks and languages. +- Allow users to rate and comment on shared presets, fostering a collaborative environment. 3. **Educational Content and Tutorials:** - - Provide users with tutorials and guides on how to effectively use the temperature control for various coding tasks. - - Offer insights and tips on optimizing AI-assisted coding based on the temperature settings. +- Provide users with tutorials and guides on how to effectively use the temperature control for various coding tasks. +- Offer insights and tips on optimizing AI-assisted coding based on the temperature settings. #### Continuous Improvement: - **User Feedback Loop:** Regularly collect user feedback to understand their needs and pain points, adjusting the roadmap accordingly. -- **Market and Technology Trends:** Stay updated with the latest trends in AI and software development to introduce innovative features that keep the plugin relevant and useful. +- **Market and Technology Trends:** Stay updated with the latest trends in AI and software development to introduce innovative features that keep the plugin + relevant and useful. -This roadmap is subject to change based on user feedback, technological advancements, and strategic decisions. The aim is to create a dynamic and user-focused plugin that enhances the coding experience in IntelliJ IDEA. +This roadmap is subject to change based on user feedback, technological advancements, and strategic decisions. The aim is to create a dynamic and user-focused +plugin that enhances the coding experience in IntelliJ IDEA. # resources\sources\kt\com\github\simiacryptus\aicoder\ui\TokenCountWidgetFactory.kt -Developing a feature like the Token Count Widget for an IDE such as IntelliJ IDEA involves several stages from initial conception to final release and maintenance. Below is a detailed roadmap outlining the key phases of development for this feature. - +Developing a feature like the Token Count Widget for an IDE such as IntelliJ IDEA involves several stages from initial conception to final release and +maintenance. Below is a detailed roadmap outlining the key phases of development for this feature. #### 1. Conceptualization and Planning + - **Idea Generation:** Identify the need for a token count widget in the IDE to help developers understand the complexity and size of their code. - **Feasibility Study:** Assess the technical feasibility and the potential impact on the user experience. - **Requirements Gathering:** Define the functional and non-functional requirements for the widget. - #### 2. Design -- **Architecture Design:** Decide on the widget's architecture, including how it integrates with the IntelliJ Platform and interacts with other components. -- **UI/UX Design:** Design the user interface and experience, focusing on how the widget displays the token count and any interactions (e.g., tooltips, click actions). +- **Architecture Design:** Decide on the widget's architecture, including how it integrates with the IntelliJ Platform and interacts with other components. +- **UI/UX Design:** Design the user interface and experience, focusing on how the widget displays the token count and any interactions (e.g., tooltips, click + actions). #### 3. Implementation + - **Environment Setup:** Set up the development environment, including necessary SDKs and plugins for IntelliJ Platform development. - **Core Development:** - Implement the `TokenCountWidgetFactory` and `TokenCountWidget` classes. @@ -5403,575 +6633,681 @@ Developing a feature like the Token Count Widget for an IDE such as IntelliJ IDE - Implement threading with a `ThreadPoolExecutor` to manage token count updates without blocking the UI. - **Testing:** Write and execute unit tests and integration tests to ensure reliability and correctness. - #### 4. Review and Testing + - **Code Review:** Conduct thorough code reviews with peers to ensure code quality and adherence to best practices. - **User Testing:** Perform user acceptance testing with a select group of users to gather feedback on usability and functionality. - #### 5. Deployment + - **Packaging:** Package the widget as a plugin for the IntelliJ IDEA. - **Publishing:** Publish the plugin to the JetBrains Marketplace. - **Announcement:** Announce the release of the widget through relevant channels (e.g., forums, social media). - #### 6. Maintenance and Updates + - **Monitoring:** Monitor the widget for any issues or performance impacts in the wild. - **Feedback Collection:** Collect user feedback for future improvements. - **Updates:** Regularly update the widget for compatibility with new versions of the IntelliJ Platform and to add new features or improvements. - #### 7. Future Enhancements -- **Feature Expansion:** Consider adding more features based on user feedback, such as customizable thresholds for token counts or support for additional languages. -- **Performance Optimization:** Continuously profile and optimize the widget's performance, especially its interaction with the IntelliJ Platform's editor and file system. + +- **Feature Expansion:** Consider adding more features based on user feedback, such as customizable thresholds for token counts or support for additional + languages. +- **Performance Optimization:** Continuously profile and optimize the widget's performance, especially its interaction with the IntelliJ Platform's editor and + file system. - **Internationalization:** Add support for multiple languages to make the widget accessible to a global audience. -This roadmap provides a structured approach to developing the Token Count Widget, ensuring that the feature is well-designed, implemented correctly, and provides value to the end-users. +This roadmap provides a structured approach to developing the Token Count Widget, ensuring that the feature is well-designed, implemented correctly, and +provides value to the end-users. # resources\sources\kt\com\github\simiacryptus\aicoder\util\CodeChatSocketManager.kt - #### Feature Development Roadmap for CodeChatSocketManager -The `CodeChatSocketManager` class is designed to integrate a coding assistance chat feature into an application, leveraging OpenAI's language models. This roadmap outlines the planned features and improvements to enhance its functionality, user experience, and integration capabilities. - +The `CodeChatSocketManager` class is designed to integrate a coding assistance chat feature into an application, leveraging OpenAI's language models. This +roadmap outlines the planned features and improvements to enhance its functionality, user experience, and integration capabilities. ##### Phase 1: Core Functionality Enhancements 1. **Improved Code Parsing and Highlighting** - - Implement advanced code parsing to better understand the structure and semantics of the provided code snippet. - - Enhance syntax highlighting based on the `language` parameter to support a wider range of programming languages. + +- Implement advanced code parsing to better understand the structure and semantics of the provided code snippet. +- Enhance syntax highlighting based on the `language` parameter to support a wider range of programming languages. 2. **Contextual Help and Suggestions** - - Develop a feature to provide contextual help and suggestions based on the current cursor position or selected code within the chat interface. + +- Develop a feature to provide contextual help and suggestions based on the current cursor position or selected code within the chat interface. 3. **Integration with Code Repositories** - - Enable linking with popular code repositories (e.g., GitHub, GitLab) to directly fetch and update code snippets. + +- Enable linking with popular code repositories (e.g., GitHub, GitLab) to directly fetch and update code snippets. 4. **Custom Model Training** - - Explore the possibility of training the OpenAITextModel on domain-specific codebases to provide more accurate and relevant assistance. +- Explore the possibility of training the OpenAITextModel on domain-specific codebases to provide more accurate and relevant assistance. ##### Phase 2: User Experience Improvements 1. **Interactive Code Editing** - - Allow users to edit code directly within the chat interface and receive real-time feedback and suggestions from the AI. + +- Allow users to edit code directly within the chat interface and receive real-time feedback and suggestions from the AI. 2. **Multi-Language Support** - - Extend support for additional programming languages based on user demand and feedback. + +- Extend support for additional programming languages based on user demand and feedback. 3. **User Customization Options** - - Provide users with options to customize the appearance and behavior of the chat interface, including theme, font size, and syntax highlighting preferences. + +- Provide users with options to customize the appearance and behavior of the chat interface, including theme, font size, and syntax highlighting preferences. 4. **Accessibility Enhancements** - - Implement accessibility features to ensure the chat interface is usable by people with disabilities, including keyboard navigation and screen reader support. +- Implement accessibility features to ensure the chat interface is usable by people with disabilities, including keyboard navigation and screen reader + support. ##### Phase 3: Collaboration and Community Features 1. **Live Collaboration Mode** - - Introduce a feature for multiple users to collaborate on the same code snippet in real-time within the chat interface. + +- Introduce a feature for multiple users to collaborate on the same code snippet in real-time within the chat interface. 2. **Community-Driven Q&A** - - Develop a community-driven Q&A feature where users can ask and answer questions related to the code snippet, with the best responses highlighted by the AI. + +- Develop a community-driven Q&A feature where users can ask and answer questions related to the code snippet, with the best responses highlighted by the AI. 3. **Feedback and Rating System** - - Implement a feedback and rating system for users to rate the helpfulness of AI-generated responses, which can be used to improve response quality over time. + +- Implement a feedback and rating system for users to rate the helpfulness of AI-generated responses, which can be used to improve response quality over time. 4. **Integration with Development Environments** - - Develop plugins or extensions to integrate the chat feature directly into popular Integrated Development Environments (IDEs) and code editors. +- Develop plugins or extensions to integrate the chat feature directly into popular Integrated Development Environments (IDEs) and code editors. ##### Phase 4: Security and Compliance 1. **Code Privacy and Security** - - Implement robust security measures to ensure that code shared within the chat interface is kept private and secure. + +- Implement robust security measures to ensure that code shared within the chat interface is kept private and secure. 2. **Compliance and Ethics Guidelines** - - Develop and enforce guidelines to ensure the ethical use of the AI, including preventing the generation of malicious code. + +- Develop and enforce guidelines to ensure the ethical use of the AI, including preventing the generation of malicious code. 3. **Audit Trails and Monitoring** - - Introduce audit trails and monitoring features to track usage and detect any potential misuse of the chat feature. +- Introduce audit trails and monitoring features to track usage and detect any potential misuse of the chat feature. ##### Phase 5: Scalability and Performance Optimization 1. **Load Balancing and Scalability** - - Optimize the backend infrastructure to handle a high number of concurrent users and ensure smooth performance during peak usage. + +- Optimize the backend infrastructure to handle a high number of concurrent users and ensure smooth performance during peak usage. 2. **Caching and Optimization** - - Implement caching strategies and optimize API calls to reduce latency and improve the responsiveness of the chat interface. + +- Implement caching strategies and optimize API calls to reduce latency and improve the responsiveness of the chat interface. 3. **Monitoring and Analytics** - - Integrate monitoring and analytics tools to track usage patterns, identify bottlenecks, and inform future improvements. -This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The development team is committed to delivering a high-quality, user-friendly coding assistance chat feature that meets the needs of its users. +- Integrate monitoring and analytics tools to track usage patterns, identify bottlenecks, and inform future improvements. -# resources\sources\kt\com\github\simiacryptus\aicoder\util\BlockComment.kt +This roadmap is subject to change based on user feedback, technological advancements, and strategic priorities. The development team is committed to delivering +a high-quality, user-friendly coding assistance chat feature that meets the needs of its users. -The `BlockComment` class is a specialized utility designed for handling block comments in a structured and manipulable way. It extends the functionality of `IndentedText` by incorporating block prefixes, line prefixes, and block suffixes, making it highly suitable for generating or parsing block comments in various programming languages. Below is a proposed feature development roadmap to enhance its capabilities and utility further. +# resources\sources\kt\com\github\simiacryptus\aicoder\util\BlockComment.kt +The `BlockComment` class is a specialized utility designed for handling block comments in a structured and manipulable way. It extends the functionality of +`IndentedText` by incorporating block prefixes, line prefixes, and block suffixes, making it highly suitable for generating or parsing block comments in various +programming languages. Below is a proposed feature development roadmap to enhance its capabilities and utility further. #### Phase 1: Core Functionality Enhancements -- **Refinement of Parsing Logic**: Improve the parsing logic to handle edge cases more gracefully, such as nested block comments or comments with embedded code snippets. -- **Support for More Languages**: Extend the `Factory` class to support block comment syntax for additional programming languages, making the utility more versatile. -- **Performance Optimization**: Optimize the internal string manipulation and stream processing to handle large text blocks more efficiently. +- **Refinement of Parsing Logic**: Improve the parsing logic to handle edge cases more gracefully, such as nested block comments or comments with embedded code + snippets. +- **Support for More Languages**: Extend the `Factory` class to support block comment syntax for additional programming languages, making the utility more + versatile. +- **Performance Optimization**: Optimize the internal string manipulation and stream processing to handle large text blocks more efficiently. #### Phase 2: Usability Improvements + - **API Documentation**: Develop comprehensive API documentation, including examples for common use cases, to make the utility more accessible to new users. - **Error Handling and Validation**: Implement robust error handling and input validation to provide clear feedback on misuse or incorrect inputs. -- **Configurable Formatting Options**: Introduce options for configuring the formatting of the output, such as controlling the spacing around line prefixes or the alignment of text within the block comment. - +- **Configurable Formatting Options**: Introduce options for configuring the formatting of the output, such as controlling the spacing around line prefixes or + the alignment of text within the block comment. #### Phase 3: Advanced Features -- **Comment Manipulation Tools**: Add methods for common comment manipulations, such as appending to, removing from, or modifying specific lines within a block comment. -- **Integration with Code Formatters**: Provide integration capabilities with popular code formatters to ensure that generated block comments adhere to project-specific formatting guidelines. -- **Annotation Support**: Implement functionality to parse and generate annotated block comments, allowing for richer metadata to be embedded within comments. +- **Comment Manipulation Tools**: Add methods for common comment manipulations, such as appending to, removing from, or modifying specific lines within a block + comment. +- **Integration with Code Formatters**: Provide integration capabilities with popular code formatters to ensure that generated block comments adhere to + project-specific formatting guidelines. +- **Annotation Support**: Implement functionality to parse and generate annotated block comments, allowing for richer metadata to be embedded within comments. #### Phase 4: Ecosystem Integration -- **IDE Plugins**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA and Visual Studio Code, offering seamless integration of the utility's capabilities directly within the development workflow. -- **Build Tools and CI/CD Integration**: Provide integration modules for build tools (e.g., Maven, Gradle) and Continuous Integration/Continuous Deployment (CI/CD) pipelines, enabling automated comment generation and validation as part of the build process. -- **Community Contributions**: Establish a framework for community contributions, including a contribution guide, issue templates, and a process for submitting and reviewing patches or feature enhancements. +- **IDE Plugins**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA and Visual Studio Code, offering seamless + integration of the utility's capabilities directly within the development workflow. +- **Build Tools and CI/CD Integration**: Provide integration modules for build tools (e.g., Maven, Gradle) and Continuous Integration/Continuous Deployment ( + CI/CD) pipelines, enabling automated comment generation and validation as part of the build process. +- **Community Contributions**: Establish a framework for community contributions, including a contribution guide, issue templates, and a process for submitting + and reviewing patches or feature enhancements. #### Phase 5: Future Directions -- **Machine Learning-Assisted Comment Generation**: Explore the integration of machine learning models to automatically generate meaningful block comments based on code analysis. -- **Localization and Internationalization**: Add support for generating block comments in multiple languages, catering to international development teams and documentation requirements. -- **Semantic Comment Analysis**: Develop tools for semantic analysis of block comments, enabling features like automatic summarization, categorization, and relevance scoring of comments in large codebases. -This roadmap outlines a comprehensive strategy for evolving the `BlockComment` utility into a powerful tool for developers, enhancing code readability, maintainability, and documentation quality across a wide range of programming languages and development environments. +- **Machine Learning-Assisted Comment Generation**: Explore the integration of machine learning models to automatically generate meaningful block comments based + on code analysis. +- **Localization and Internationalization**: Add support for generating block comments in multiple languages, catering to international development teams and + documentation requirements. +- **Semantic Comment Analysis**: Develop tools for semantic analysis of block comments, enabling features like automatic summarization, categorization, and + relevance scoring of comments in large codebases. -# resources\sources\kt\com\github\simiacryptus\aicoder\util\DiffMatchPatch.kt +This roadmap outlines a comprehensive strategy for evolving the `BlockComment` utility into a powerful tool for developers, enhancing code readability, +maintainability, and documentation quality across a wide range of programming languages and development environments. -Developing a feature involves multiple stages, from initial ideation to final release and maintenance. Below is a comprehensive roadmap for feature development, tailored to ensure a structured and efficient approach to bringing new features from concept to reality. +# resources\sources\kt\com\github\simiacryptus\aicoder\util\DiffMatchPatch.kt +Developing a feature involves multiple stages, from initial ideation to final release and maintenance. Below is a comprehensive roadmap for feature development, +tailored to ensure a structured and efficient approach to bringing new features from concept to reality. #### 1. Ideation and Conceptualization + - **Idea Generation:** Encourage open brainstorming sessions among team members to generate new ideas. - **Feasibility Study:** Assess the technical feasibility, market demand, and alignment with business goals. - **Concept Approval:** Present the concept to stakeholders for initial approval. - #### 2. Research and Analysis + - **Market Research:** Analyze market trends, competitor features, and customer feedback to validate the need for the feature. - **Requirement Gathering:** Collect detailed requirements from stakeholders, including potential users and technical teams. - **Risk Analysis:** Identify potential risks and mitigation strategies. - #### 3. Planning + - **Roadmap Development:** Create a detailed roadmap with milestones, timelines, and resource allocation. - **Technical Specification:** Draft technical specifications and architecture designs. - **Prototyping:** Develop a prototype or mock-up to visualize the feature. - #### 4. Design + - **UI/UX Design:** Design user interfaces and experiences, focusing on usability and accessibility. - **Feedback Loop:** Conduct user testing with the prototype and refine designs based on feedback. - #### 5. Development + - **Agile Sprints:** Break down the development process into sprints, focusing on incremental progress. - **Code Reviews:** Implement regular code reviews to maintain code quality. - **Continuous Integration:** Use CI tools to automate testing and integration. - #### 6. Testing + - **Unit Testing:** Write and execute unit tests to cover individual components. - **Integration Testing:** Ensure that different parts of the application work together as expected. - **User Acceptance Testing (UAT):** Validate the feature with end-users to ensure it meets their needs and expectations. - #### 7. Deployment + - **Staging Environment:** Deploy the feature to a staging environment for final testing. - **Deployment Plan:** Create a detailed deployment plan, including rollback procedures. - **Release:** Gradually release the feature to users, possibly using feature flags for controlled rollout. - #### 8. Post-Release + - **Monitoring:** Closely monitor the feature for any issues or unexpected behavior. - **User Feedback:** Collect and analyze user feedback for future improvements. - **Maintenance:** Regularly update the feature to fix bugs, improve performance, and add enhancements. - #### 9. Evaluation + - **Performance Metrics:** Evaluate the feature's performance against predefined KPIs and metrics. - **Retrospective:** Conduct a retrospective meeting to discuss what went well, what didn't, and lessons learned. - **Future Roadmap:** Update the product roadmap based on the feature's performance and user feedback. - #### 10. Documentation and Training + - **Documentation:** Update technical and user documentation to include the new feature. - **Training:** Provide training for end-users and internal teams as necessary. -This roadmap is iterative and cyclical; the insights gained from the evaluation phase can lead to new ideas and improvements, feeding back into the ideation phase for future features. +This roadmap is iterative and cyclical; the insights gained from the evaluation phase can lead to new ideas and improvements, feeding back into the ideation +phase for future features. # resources\sources\kt\com\github\simiacryptus\aicoder\util\ComputerLanguage.kt -Developing a feature roadmap for the `ComputerLanguage` enum and its associated classes within the `com.github.simiacryptus.aicoder.util` package involves planning enhancements, optimizations, and new capabilities that can be added to improve its functionality, usability, and integration capabilities. Here's a proposed development roadmap: - +Developing a feature roadmap for the `ComputerLanguage` enum and its associated classes within the `com.simiacryptus.aicoder.util` package involves planning +enhancements, optimizations, and new capabilities that can be added to improve its functionality, usability, and integration capabilities. Here's a proposed +development roadmap: #### Phase 1: Core Enhancements -- **Refactor Configuration Class**: Improve the internal structure of the `Configuration` class for better readability and maintainability. Consider making `blockComments` and `docComments` non-nullable and providing default values. -- **Expand Language Support**: Add more programming languages to the `ComputerLanguage` enum, focusing on emerging and popular languages not currently covered. -- **Improve Documentation**: Enhance the inline documentation within the code, ensuring that each method, class, and enum is clearly described, making the codebase more accessible to new contributors. +- **Refactor Configuration Class**: Improve the internal structure of the `Configuration` class for better readability and maintainability. Consider making + `blockComments` and `docComments` non-nullable and providing default values. +- **Expand Language Support**: Add more programming languages to the `ComputerLanguage` enum, focusing on emerging and popular languages not currently covered. +- **Improve Documentation**: Enhance the inline documentation within the code, ensuring that each method, class, and enum is clearly described, making the + codebase more accessible to new contributors. #### Phase 2: Usability Improvements -- **Intuitive API**: Develop a more intuitive API for creating and modifying language configurations, making it easier for users to customize comment styles and other language-specific settings. -- **Configuration Validation**: Implement validation logic within the `Configuration` class to ensure that all necessary properties are set before a `ComputerLanguage` instance is created. -- **Dynamic Language Configuration**: Allow dynamic addition or modification of language configurations at runtime, enabling users to add support for new languages without modifying the source code. +- **Intuitive API**: Develop a more intuitive API for creating and modifying language configurations, making it easier for users to customize comment styles and + other language-specific settings. +- **Configuration Validation**: Implement validation logic within the `Configuration` class to ensure that all necessary properties are set before a + `ComputerLanguage` instance is created. +- **Dynamic Language Configuration**: Allow dynamic addition or modification of language configurations at runtime, enabling users to add support for new + languages without modifying the source code. #### Phase 3: Integration and Tooling -- **IDE Plugin Development**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code, integrating the functionality directly into the development workflow. -- **Command-Line Interface (CLI)**: Create a CLI tool for performing operations supported by the `ComputerLanguage` class, such as finding a language by extension or generating comment blocks. -- **Configuration Export/Import**: Implement functionality to export and import language configurations as JSON or XML, facilitating easy sharing and versioning of custom configurations. +- **IDE Plugin Development**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code, + integrating the functionality directly into the development workflow. +- **Command-Line Interface (CLI)**: Create a CLI tool for performing operations supported by the `ComputerLanguage` class, such as finding a language by + extension or generating comment blocks. +- **Configuration Export/Import**: Implement functionality to export and import language configurations as JSON or XML, facilitating easy sharing and versioning + of custom configurations. #### Phase 4: Advanced Features -- **Syntax Highlighting**: Integrate syntax highlighting capabilities for supported languages, improving the visualization of code and comments within the IDE plugins. -- **Code Analysis Tools**: Develop code analysis tools that leverage the `ComputerLanguage` configurations to detect issues with comment usage, documentation coverage, and adherence to language-specific best practices. -- **Machine Learning Integration**: Explore the integration of machine learning models to automatically generate documentation comments based on code analysis, reducing the manual effort required for documentation. +- **Syntax Highlighting**: Integrate syntax highlighting capabilities for supported languages, improving the visualization of code and comments within the IDE + plugins. +- **Code Analysis Tools**: Develop code analysis tools that leverage the `ComputerLanguage` configurations to detect issues with comment usage, documentation + coverage, and adherence to language-specific best practices. +- **Machine Learning Integration**: Explore the integration of machine learning models to automatically generate documentation comments based on code analysis, + reducing the manual effort required for documentation. #### Phase 5: Community and Collaboration -- **Open Source Contributions**: Encourage community contributions by setting up a clear contribution guideline, issue tracking, and feature request system. -- **Documentation and Tutorials**: Create comprehensive documentation, tutorials, and examples showcasing how to use the library and contribute to its development. -- **Integration with Other Projects**: Collaborate with authors of related projects to provide seamless integration, enhancing the ecosystem around code documentation and language support. +- **Open Source Contributions**: Encourage community contributions by setting up a clear contribution guideline, issue tracking, and feature request system. +- **Documentation and Tutorials**: Create comprehensive documentation, tutorials, and examples showcasing how to use the library and contribute to its + development. +- **Integration with Other Projects**: Collaborate with authors of related projects to provide seamless integration, enhancing the ecosystem around code + documentation and language support. #### Phase 6: Performance and Optimization -- **Benchmarking and Profiling**: Conduct thorough benchmarking and profiling to identify performance bottlenecks and optimize the code for speed and memory usage. + +- **Benchmarking and Profiling**: Conduct thorough benchmarking and profiling to identify performance bottlenecks and optimize the code for speed and memory + usage. - **Parallel Processing**: Explore opportunities for parallel processing, especially in IDE plugins and CLI tools, to improve performance for large projects. -This roadmap is designed to be iterative, allowing for adjustments and additions based on user feedback, technological advancements, and the evolving needs of the developer community. +This roadmap is designed to be iterative, allowing for adjustments and additions based on user feedback, technological advancements, and the evolving needs of +the developer community. # resources\sources\kt\com\github\simiacryptus\aicoder\util\IdeaKotlinInterpreter.kt -Creating a feature development roadmap for the `IdeaKotlinInterpreter` class involves outlining a series of enhancements and new functionalities that can be added to improve its capabilities, performance, and user experience. This roadmap will be divided into short-term, mid-term, and long-term goals, each with specific features and improvements. - +Creating a feature development roadmap for the `IdeaKotlinInterpreter` class involves outlining a series of enhancements and new functionalities that can be +added to improve its capabilities, performance, and user experience. This roadmap will be divided into short-term, mid-term, and long-term goals, each with +specific features and improvements. #### Short-Term Goals (1-3 Months) 1. **Enhanced Error Handling and Logging**: - - Implement more detailed error messages and exceptions handling to make debugging easier for users. - - Integrate a logging framework to provide users with runtime information and error logs. + +- Implement more detailed error messages and exceptions handling to make debugging easier for users. +- Integrate a logging framework to provide users with runtime information and error logs. 2. **Performance Optimization**: - - Profile the current implementation to identify bottlenecks. - - Optimize the script engine initialization and code wrapping process for faster execution. + +- Profile the current implementation to identify bottlenecks. +- Optimize the script engine initialization and code wrapping process for faster execution. 3. **Documentation and Examples**: - - Create comprehensive documentation covering all functionalities and use cases. - - Provide a set of example scripts and use cases to help new users get started. + +- Create comprehensive documentation covering all functionalities and use cases. +- Provide a set of example scripts and use cases to help new users get started. 4. **Unit Testing**: - - Develop a suite of unit tests to ensure the reliability and stability of key functionalities. - - Integrate continuous integration (CI) tools to automate testing. +- Develop a suite of unit tests to ensure the reliability and stability of key functionalities. +- Integrate continuous integration (CI) tools to automate testing. #### Mid-Term Goals (4-6 Months) 1. **Interactive Development Environment (IDE) Integration Enhancements**: - - Improve integration with IntelliJ IDEA and other JetBrains IDEs, focusing on usability and performance. - - Implement features like code completion, syntax highlighting, and debugging support for scripts executed within the interpreter. + +- Improve integration with IntelliJ IDEA and other JetBrains IDEs, focusing on usability and performance. +- Implement features like code completion, syntax highlighting, and debugging support for scripts executed within the interpreter. 2. **Extended Language Support**: - - Explore the possibility of extending the interpreter to support additional JVM languages (e.g., Groovy, Scala) within the same framework. + +- Explore the possibility of extending the interpreter to support additional JVM languages (e.g., Groovy, Scala) within the same framework. 3. **Dynamic Symbol Management**: - - Develop a more flexible system for managing symbols, allowing users to add, remove, or modify symbols at runtime. + +- Develop a more flexible system for managing symbols, allowing users to add, remove, or modify symbols at runtime. 4. **Security Features**: - - Implement security measures to prevent unauthorized code execution and access to sensitive data. +- Implement security measures to prevent unauthorized code execution and access to sensitive data. #### Long-Term Goals (7-12 Months) 1. **Plugin Ecosystem**: - - Develop an API that allows third-party developers to create plugins and extensions for the interpreter, enhancing its functionality and versatility. + +- Develop an API that allows third-party developers to create plugins and extensions for the interpreter, enhancing its functionality and versatility. 2. **Cross-Platform Support**: - - Ensure the interpreter can be easily used across different operating systems and IDEs, broadening its user base. + +- Ensure the interpreter can be easily used across different operating systems and IDEs, broadening its user base. 3. **Cloud Integration**: - - Provide features for executing scripts in cloud environments, facilitating distributed computing and remote development scenarios. + +- Provide features for executing scripts in cloud environments, facilitating distributed computing and remote development scenarios. 4. **Community Building**: - - Foster a community of users and developers through forums, social media, and events to gather feedback, share knowledge, and drive the project's direction. + +- Foster a community of users and developers through forums, social media, and events to gather feedback, share knowledge, and drive the project's direction. 5. **Advanced Debugging Tools**: - - Develop advanced debugging tools that integrate seamlessly with the interpreter, offering features like breakpoint management, variable inspection, and execution flow control. -By following this roadmap, the `IdeaKotlinInterpreter` can evolve into a more powerful, user-friendly, and widely adopted tool for Kotlin script execution within the IntelliJ IDEA environment and beyond. +- Develop advanced debugging tools that integrate seamlessly with the interpreter, offering features like breakpoint management, variable inspection, and + execution flow control. -# resources\sources\kt\com\github\simiacryptus\aicoder\util\LineComment.kt +By following this roadmap, the `IdeaKotlinInterpreter` can evolve into a more powerful, user-friendly, and widely adopted tool for Kotlin script execution +within the IntelliJ IDEA environment and beyond. -The code snippet provided is part of a larger project aimed at enhancing text manipulation and formatting capabilities, particularly focusing on handling line comments within a given text block. To further develop this project and expand its utility, a feature development roadmap is proposed. This roadmap outlines a series of planned features and improvements, structured in phases to guide the project's progression. +# resources\sources\kt\com\github\simiacryptus\aicoder\util\LineComment.kt +The code snippet provided is part of a larger project aimed at enhancing text manipulation and formatting capabilities, particularly focusing on handling line +comments within a given text block. To further develop this project and expand its utility, a feature development roadmap is proposed. This roadmap outlines a +series of planned features and improvements, structured in phases to guide the project's progression. #### Phase 1: Core Functionality Enhancements -1. **Multi-Language Support**: Extend the `LineComment` class to support comment prefixes for multiple programming languages, enabling users to work with a broader range of source code files. - -2. **Automatic Indentation Detection**: Improve the indentation detection mechanism to automatically adjust to the source code's existing indentation style, enhancing the tool's adaptability. +1. **Multi-Language Support**: Extend the `LineComment` class to support comment prefixes for multiple programming languages, enabling users to work with a + broader range of source code files. -3. **Comment Block Handling**: Develop functionality to handle block comments in addition to line comments, allowing for more comprehensive text manipulation capabilities. +2. **Automatic Indentation Detection**: Improve the indentation detection mechanism to automatically adjust to the source code's existing indentation style, + enhancing the tool's adaptability. +3. **Comment Block Handling**: Develop functionality to handle block comments in addition to line comments, allowing for more comprehensive text manipulation + capabilities. #### Phase 2: Usability Improvements -4. **Interactive CLI Tool**: Create a Command Line Interface (CLI) tool that allows users to apply the library's functionalities interactively, improving accessibility for non-programmatic users. - -5. **Configuration File Support**: Implement support for configuration files, enabling users to define and save their preferences for comment styles, indentation, and other settings. +4. **Interactive CLI Tool**: Create a Command Line Interface (CLI) tool that allows users to apply the library's functionalities interactively, improving + accessibility for non-programmatic users. -6. **Error Handling and Validation**: Enhance error handling and input validation to provide clear feedback to users, improving the tool's robustness and user experience. +5. **Configuration File Support**: Implement support for configuration files, enabling users to define and save their preferences for comment styles, + indentation, and other settings. +6. **Error Handling and Validation**: Enhance error handling and input validation to provide clear feedback to users, improving the tool's robustness and user + experience. #### Phase 3: Integration and Expansion -7. **IDE Plugin Development**: Develop plugins for popular Integrated Development Environments (IDEs) such as IntelliJ IDEA and Visual Studio Code, integrating the library's functionalities directly into the development workflow. +7. **IDE Plugin Development**: Develop plugins for popular Integrated Development Environments (IDEs) such as IntelliJ IDEA and Visual Studio Code, integrating + the library's functionalities directly into the development workflow. 8. **API and Web Service**: Expose the library's functionalities through a RESTful API or as a web service, enabling integration with other tools and services. -9. **Documentation and Tutorials**: Create comprehensive documentation and tutorials to assist users in understanding and leveraging the library's full capabilities. - +9. **Documentation and Tutorials**: Create comprehensive documentation and tutorials to assist users in understanding and leveraging the library's full + capabilities. #### Phase 4: Advanced Features and Research -10. **Machine Learning-Based Formatting**: Research and implement machine learning algorithms to predict and apply optimal formatting styles based on the source code's context and user preferences. - -11. **Collaborative Editing Support**: Explore features to support collaborative editing scenarios, such as real-time comment and formatting synchronization across multiple users. +10. **Machine Learning-Based Formatting**: Research and implement machine learning algorithms to predict and apply optimal formatting styles based on the source + code's context and user preferences. -12. **Customizable Formatting Rules**: Allow users to define and share their own formatting rules and styles, fostering a community-driven approach to code formatting standards. +11. **Collaborative Editing Support**: Explore features to support collaborative editing scenarios, such as real-time comment and formatting synchronization + across multiple users. +12. **Customizable Formatting Rules**: Allow users to define and share their own formatting rules and styles, fostering a community-driven approach to code + formatting standards. #### Conclusion -This roadmap outlines a strategic approach to developing a comprehensive text manipulation and formatting tool, focusing on enhancing functionality, usability, integration, and advanced features. By following this roadmap, the project aims to provide a versatile and user-friendly tool that meets the needs of a wide range of users, from individual developers to large teams working in diverse programming environments. +This roadmap outlines a strategic approach to developing a comprehensive text manipulation and formatting tool, focusing on enhancing functionality, usability, +integration, and advanced features. By following this roadmap, the project aims to provide a versatile and user-friendly tool that meets the needs of a wide +range of users, from individual developers to large teams working in diverse programming environments. # resources\sources\kt\com\github\simiacryptus\aicoder\util\IdeaOpenAIClient.kt -Developing a feature roadmap for the `IdeaOpenAIClient` class involves planning out enhancements, optimizations, and new functionalities that can be added to improve its integration with OpenAI's API and its utility within an IDE environment. Below is a proposed roadmap that outlines potential directions for future development: - +Developing a feature roadmap for the `IdeaOpenAIClient` class involves planning out enhancements, optimizations, and new functionalities that can be added to +improve its integration with OpenAI's API and its utility within an IDE environment. Below is a proposed roadmap that outlines potential directions for future +development: #### Phase 1: Initial Enhancements and Optimizations -- **Logging Improvements**: Enhance the logging mechanism to include more detailed information about requests and responses, including timestamps and request IDs, to facilitate debugging and monitoring. -- **Performance Optimization**: Analyze and optimize performance, particularly focusing on reducing latency in the `chat`, `complete`, and `edit` methods when interacting with the OpenAI API. -- **Error Handling**: Implement more robust error handling and retry mechanisms to manage API rate limits and transient network issues gracefully. +- **Logging Improvements**: Enhance the logging mechanism to include more detailed information about requests and responses, including timestamps and request + IDs, to facilitate debugging and monitoring. +- **Performance Optimization**: Analyze and optimize performance, particularly focusing on reducing latency in the `chat`, `complete`, and `edit` methods when + interacting with the OpenAI API. +- **Error Handling**: Implement more robust error handling and retry mechanisms to manage API rate limits and transient network issues gracefully. #### Phase 2: User Experience Enhancements -- **Interactive Configuration UI**: Develop a user-friendly configuration interface within the IDE for setting and updating API keys and other settings without editing configuration files. -- **Request Editing UI Improvements**: Enhance the request editing dialog to support syntax highlighting and validation for JSON, making it easier for users to construct and edit requests. -- **Progress Indicators**: Introduce progress indicators for long-running requests to keep users informed about the status of their interactions with the OpenAI API. +- **Interactive Configuration UI**: Develop a user-friendly configuration interface within the IDE for setting and updating API keys and other settings without + editing configuration files. +- **Request Editing UI Improvements**: Enhance the request editing dialog to support syntax highlighting and validation for JSON, making it easier for users to + construct and edit requests. +- **Progress Indicators**: Introduce progress indicators for long-running requests to keep users informed about the status of their interactions with the OpenAI + API. #### Phase 3: Advanced Features -- **Model Management**: Add functionality to list, select, and manage OpenAI models directly from the IDE, allowing users to easily switch between models for different tasks. -- **Local Caching**: Implement a caching mechanism to store responses for frequently made requests, reducing API usage and improving response times for repeated queries. -- **Collaborative Features**: Explore the integration of collaborative features that allow teams to share and manage API keys, request templates, and responses within a shared workspace. +- **Model Management**: Add functionality to list, select, and manage OpenAI models directly from the IDE, allowing users to easily switch between models for + different tasks. +- **Local Caching**: Implement a caching mechanism to store responses for frequently made requests, reducing API usage and improving response times for repeated + queries. +- **Collaborative Features**: Explore the integration of collaborative features that allow teams to share and manage API keys, request templates, and responses + within a shared workspace. #### Phase 4: Integration and Expansion -- **Extended IDE Support**: Expand the client's compatibility to work seamlessly with other IDEs beyond IntelliJ, such as VS Code or Eclipse, broadening its user base. -- **Plugin Ecosystem**: Develop a plugin ecosystem that allows third-party developers to extend the functionality of the `IdeaOpenAIClient`, such as adding support for additional languages or integrating with other tools and services. -- **AI-Assisted Coding**: Investigate the integration of AI-assisted coding features, leveraging OpenAI's capabilities to suggest code completions, refactorings, and optimizations based on the current codebase and context. +- **Extended IDE Support**: Expand the client's compatibility to work seamlessly with other IDEs beyond IntelliJ, such as VS Code or Eclipse, broadening its + user base. +- **Plugin Ecosystem**: Develop a plugin ecosystem that allows third-party developers to extend the functionality of the `IdeaOpenAIClient`, such as adding + support for additional languages or integrating with other tools and services. +- **AI-Assisted Coding**: Investigate the integration of AI-assisted coding features, leveraging OpenAI's capabilities to suggest code completions, + refactorings, and optimizations based on the current codebase and context. #### Phase 5: Security and Compliance -- **Security Audits**: Conduct regular security audits to identify and mitigate potential vulnerabilities, particularly focusing on secure handling of API keys and user data. -- **Compliance Features**: Implement features to help users comply with relevant regulations and guidelines when using AI services, such as logging consent for data processing and managing data retention policies. +- **Security Audits**: Conduct regular security audits to identify and mitigate potential vulnerabilities, particularly focusing on secure handling of API keys + and user data. +- **Compliance Features**: Implement features to help users comply with relevant regulations and guidelines when using AI services, such as logging consent for + data processing and managing data retention policies. #### Phase 6: Community and Documentation -- **Community Engagement**: Foster a community of users and contributors through forums, GitHub, or other platforms to gather feedback, offer support, and guide the project's future direction. -- **Comprehensive Documentation**: Develop comprehensive documentation covering setup, usage, best practices, and examples to help users get the most out of the `IdeaOpenAIClient`. -This roadmap is intended to be iterative and flexible, with priorities adjusted based on user feedback, technological advancements, and the evolving landscape of AI services. +- **Community Engagement**: Foster a community of users and contributors through forums, GitHub, or other platforms to gather feedback, offer support, and guide + the project's future direction. +- **Comprehensive Documentation**: Develop comprehensive documentation covering setup, usage, best practices, and examples to help users get the most out of the + `IdeaOpenAIClient`. -# resources\sources\kt\com\github\simiacryptus\aicoder\util\diff_match_patch.kt +This roadmap is intended to be iterative and flexible, with priorities adjusted based on user feedback, technological advancements, and the evolving landscape +of AI services. -Developing a feature roadmap involves outlining the key steps and milestones from the conception of a feature to its release and subsequent updates. Below is a generic roadmap for feature development, adaptable to various projects and organizational structures. +# resources\sources\kt\com\github\simiacryptus\aicoder\util\diff_match_patch.kt +Developing a feature roadmap involves outlining the key steps and milestones from the conception of a feature to its release and subsequent updates. Below is a +generic roadmap for feature development, adaptable to various projects and organizational structures. #### 1. Ideation and Conceptualization + - **Market Research:** Understand user needs, market trends, and competitor analysis. - **Idea Generation:** Brainstorming sessions with stakeholders to generate potential feature ideas. - **Feasibility Study:** Evaluate technical feasibility, resource requirements, and potential ROI. - **Concept Approval:** Secure approval from decision-makers to proceed with the concept. - #### 2. Planning + - **Requirements Gathering:** Detailed collection of user stories, use cases, and functional requirements. - **Scope Definition:** Clearly define what is in and out of scope for the feature development. - **Roadmap Creation:** Develop a high-level roadmap with key milestones and timelines. - **Resource Allocation:** Assign team members, budget, and other resources needed for development. - #### 3. Design + - **UX/UI Design:** Design user interfaces and experiences, including wireframes and prototypes. - **Technical Architecture:** Define the technical architecture, data models, and integration points. - **Design Review:** Conduct reviews with stakeholders to validate design decisions. - #### 4. Development + - **Environment Setup:** Prepare development, testing, and staging environments. - **Coding:** Start the development process based on the defined requirements and designs. - **Continuous Integration:** Implement CI/CD pipelines for automated building, testing, and deployment. - #### 5. Testing and Quality Assurance + - **Unit Testing:** Developers write and run unit tests to ensure code quality. - **Integration Testing:** Test the feature in conjunction with existing system components. - **User Acceptance Testing (UAT):** End-users test the feature to validate it meets their requirements. - **Bug Fixing:** Address and resolve any issues identified during testing phases. - #### 6. Deployment + - **Deployment Planning:** Plan the deployment process, including timing and rollback procedures. - **Staging Deployment:** Deploy the feature to a staging environment for final testing. - **Production Deployment:** Release the feature to the production environment. - **Monitoring:** Monitor the feature for any issues post-deployment. - #### 7. Post-Launch + - **User Feedback:** Collect and analyze user feedback on the new feature. - **Performance Analysis:** Review feature performance against key metrics and objectives. - **Iterative Improvement:** Plan and implement improvements based on feedback and performance data. - **Documentation:** Update documentation to reflect the new feature and any changes to the system. - #### 8. Maintenance and Support + - **Bug Fixes:** Continuously address any bugs or issues that arise. - **Feature Enhancements:** Plan and implement feature enhancements as part of the product's evolution. - **Support:** Provide ongoing support to users for any issues or questions related to the feature. - #### 9. Retirement + - **Deprecation Plan:** If necessary, plan for the feature's deprecation, including user communication and migration strategies. - **Archiving Data:** Ensure that any data related to the feature is properly archived or migrated. - **Removal:** Remove the feature from the product in a way that minimizes disruption to users. -This roadmap is a guideline and can be adapted based on the specific needs of the project, the development methodology (e.g., Agile, Waterfall), and the organizational structure. +This roadmap is a guideline and can be adapted based on the specific needs of the project, the development methodology (e.g., Agile, Waterfall), and the +organizational structure. # resources\sources\kt\com\github\simiacryptus\aicoder\util\psi\PsiClassContext.kt -Creating a feature development roadmap for the `PsiClassContext` class and its associated functionalities involves outlining a series of enhancements and new features that could be added to improve its capabilities, usability, and integration with other systems or tools. Below is a proposed roadmap that outlines potential phases of development, each with its set of features and improvements. - +Creating a feature development roadmap for the `PsiClassContext` class and its associated functionalities involves outlining a series of enhancements and new +features that could be added to improve its capabilities, usability, and integration with other systems or tools. Below is a proposed roadmap that outlines +potential phases of development, each with its set of features and improvements. #### Phase 1: Core Functionality Enhancements - ##### 1.1 Improved Language Support -- Extend the `PsiClassContext` to support additional programming languages beyond Java, Kotlin, and Scala, such as Python, C++, and JavaScript. +- Extend the `PsiClassContext` to support additional programming languages beyond Java, Kotlin, and Scala, such as Python, C++, and JavaScript. ##### 1.2 Enhanced Text Range Handling -- Develop more sophisticated algorithms for determining text ranges, especially for languages with different syntax structures. +- Develop more sophisticated algorithms for determining text ranges, especially for languages with different syntax structures. ##### 1.3 Performance Optimization -- Optimize the traversal and processing of PSI elements to reduce memory usage and improve the speed of context generation. +- Optimize the traversal and processing of PSI elements to reduce memory usage and improve the speed of context generation. #### Phase 2: Usability and Integration - ##### 2.1 User Interface for Selection -- Implement a graphical user interface that allows users to visually select code segments in an editor for which they want to generate a `PsiClassContext`. +- Implement a graphical user interface that allows users to visually select code segments in an editor for which they want to generate a `PsiClassContext`. ##### 2.2 Integration with IDEs -- Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code to seamlessly use `PsiClassContext` functionalities within the IDE. +- Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code to seamlessly use `PsiClassContext` + functionalities within the IDE. ##### 2.3 Documentation and Examples + - Create comprehensive documentation and tutorials that demonstrate how to use the `PsiClassContext` class and its methods effectively. - Provide example projects showcasing practical applications of `PsiClassContext` in different scenarios. - #### Phase 3: Advanced Features - ##### 3.1 Refactoring Support -- Introduce features that leverage the `PsiClassContext` for code refactoring tasks, such as renaming variables, methods, and classes, or extracting methods. +- Introduce features that leverage the `PsiClassContext` for code refactoring tasks, such as renaming variables, methods, and classes, or extracting methods. ##### 3.2 Code Analysis and Metrics -- Develop functionalities for analyzing code complexity, detecting code smells, and generating metrics based on the structure and content of the `PsiClassContext`. +- Develop functionalities for analyzing code complexity, detecting code smells, and generating metrics based on the structure and content of the + `PsiClassContext`. ##### 3.3 Customizable Context Rules -- Allow users to define custom rules for what gets included in a `PsiClassContext`, such as filtering out certain types of elements or including additional metadata. +- Allow users to define custom rules for what gets included in a `PsiClassContext`, such as filtering out certain types of elements or including additional + metadata. #### Phase 4: Collaboration and Sharing - ##### 4.1 Sharing Contexts -- Implement features that enable users to share `PsiClassContext` instances with others, facilitating collaborative code review and discussion. +- Implement features that enable users to share `PsiClassContext` instances with others, facilitating collaborative code review and discussion. ##### 4.2 Version Control Integration -- Integrate with version control systems like Git to allow for the generation and comparison of `PsiClassContext` instances across different commits or branches. +- Integrate with version control systems like Git to allow for the generation and comparison of `PsiClassContext` instances across different commits or + branches. ##### 4.3 Cloud-Based Services -- Explore the development of cloud-based services that can generate, store, and manage `PsiClassContext` instances, providing access from anywhere and enabling more complex analyses. +- Explore the development of cloud-based services that can generate, store, and manage `PsiClassContext` instances, providing access from anywhere and enabling + more complex analyses. #### Conclusion -This roadmap outlines a strategic plan for the development of the `PsiClassContext` class and its ecosystem. By focusing on core functionality enhancements, usability improvements, advanced features, and collaboration tools, the `PsiClassContext` can become an invaluable tool for developers working with code analysis, refactoring, and understanding complex codebases. Each phase builds upon the previous one, gradually increasing the capabilities and reach of the `PsiClassContext` functionalities. +This roadmap outlines a strategic plan for the development of the `PsiClassContext` class and its ecosystem. By focusing on core functionality enhancements, +usability improvements, advanced features, and collaboration tools, the `PsiClassContext` can become an invaluable tool for developers working with code +analysis, refactoring, and understanding complex codebases. Each phase builds upon the previous one, gradually increasing the capabilities and reach of the +`PsiClassContext` functionalities. # resources\sources\kt\com\github\simiacryptus\aicoder\util\psi\PsiTranslationTree.kt -Developing a feature for a software project involves a series of steps from initial conception to final release and maintenance. Below is a detailed feature development roadmap for the `PsiTranslationTree` class within a project that aims to facilitate code translation between different programming languages. This roadmap outlines the phases of development, including planning, implementation, testing, deployment, and maintenance. - +Developing a feature for a software project involves a series of steps from initial conception to final release and maintenance. Below is a detailed feature +development roadmap for the `PsiTranslationTree` class within a project that aims to facilitate code translation between different programming languages. This +roadmap outlines the phases of development, including planning, implementation, testing, deployment, and maintenance. #### 1. Planning and Design (1-2 Weeks) + - **Requirement Analysis**: Gather and analyze requirements for the code translation feature. Understand the source and target languages supported. - **Feasibility Study**: Evaluate the technical feasibility and identify potential challenges in implementing the feature. -- **Design Specification**: Define the architecture of the `PsiTranslationTree` class, including its interactions with other components like `PsiElementVisitor`, `VirtualAPI`, and external services (e.g., `ChatProxy`). +- **Design Specification**: Define the architecture of the `PsiTranslationTree` class, including its interactions with other components like + `PsiElementVisitor`, `VirtualAPI`, and external services (e.g., `ChatProxy`). - **Prototype Design**: Create a basic prototype to explore the concept of translating code snippets using stubs and placeholders. - #### 2. Implementation (3-4 Weeks) -- **Core Development**: Start coding the main functionalities of the `PsiTranslationTree` class, focusing on parsing PSI elements and constructing a translation tree. + +- **Core Development**: Start coding the main functionalities of the `PsiTranslationTree` class, focusing on parsing PSI elements and constructing a translation + tree. - **Stub Handling**: Implement the logic for generating and replacing stubs within the code to facilitate partial translations. - **Integration with Translation API**: Develop the integration with the `VirtualAPI` for converting code snippets between languages. - **Utility Functions**: Code the utility functions for regex matching, stub replacement, and formatting translated code. - #### 3. Testing (2 Weeks) + - **Unit Testing**: Write and execute unit tests for each method in the `PsiTranslationTree` class to ensure they work as expected in isolation. - **Integration Testing**: Test the integration points, especially the interaction with the translation API and the handling of PSI elements. -- **Performance Testing**: Assess the performance, especially focusing on the efficiency of translation and the handling of large files or complex code structures. -- **User Acceptance Testing (UAT)**: Conduct UAT with a select group of users to gather feedback on the usability and effectiveness of the code translation feature. - +- **Performance Testing**: Assess the performance, especially focusing on the efficiency of translation and the handling of large files or complex code + structures. +- **User Acceptance Testing (UAT)**: Conduct UAT with a select group of users to gather feedback on the usability and effectiveness of the code translation + feature. #### 4. Deployment (1 Week) + - **Deployment Planning**: Plan the deployment process, including scheduling and resource allocation. - **Pre-Deployment Checklist**: Ensure all pre-deployment activities, such as final testing and documentation, are complete. - **Release**: Deploy the feature to the production environment. - **Post-Deployment Testing**: Perform smoke testing to ensure the feature is working as expected in the production environment. - #### 5. Documentation and Training (Ongoing) + - **Documentation**: Create comprehensive documentation covering the design, usage, and limitations of the `PsiTranslationTree` feature. - **Developer Training**: Conduct training sessions for developers to familiarize them with the feature and best practices for using it in their projects. - #### 6. Maintenance and Iteration (Ongoing) + - **Bug Fixes**: Monitor the feature for any issues or bugs reported by users and address them promptly. - **Feature Enhancements**: Based on user feedback and technological advancements, plan and implement enhancements to the feature. - **Performance Optimization**: Continuously monitor the performance and optimize as necessary to handle larger datasets or more complex translations. - #### 7. Future Roadmap Planning (Every 6 Months) + - **Evaluation**: Regularly evaluate the feature's performance, user satisfaction, and technological landscape. - **Roadmap Updates**: Update the development roadmap based on the evaluation to include new features, languages, or improvements. @@ -5979,244 +7315,280 @@ This roadmap provides a structured approach to developing the `PsiTranslationTre # resources\sources\kt\com\github\simiacryptus\aicoder\util\psi\PsiUtil.kt -Developing a feature for a software project involves a series of steps from initial conception to final release and maintenance. Below is a detailed roadmap for feature development, using the provided code example from the `PsiUtil` object in a Kotlin project as a context. This roadmap is divided into phases, each with specific goals and tasks. - +Developing a feature for a software project involves a series of steps from initial conception to final release and maintenance. Below is a detailed roadmap for +feature development, using the provided code example from the `PsiUtil` object in a Kotlin project as a context. This roadmap is divided into phases, each with +specific goals and tasks. #### Phase 1: Ideation and Planning - ##### Goals: + - Identify the need for new features or improvements in the `PsiUtil` utility class. - Define the scope and objectives of the feature development. - ##### Tasks: -1. **Requirement Gathering**: Collect feedback from users and developers about the current `PsiUtil` functionalities and potential areas for improvement or new features. -2. **Feasibility Study**: Analyze the technical feasibility and impact of the proposed features on the existing codebase. -3. **Define Scope**: Clearly outline what the new feature will and will not include, focusing on the `PsiUtil` class's capabilities related to PSI (Program Structure Interface) elements in IntelliJ-based IDEs. +1. **Requirement Gathering**: Collect feedback from users and developers about the current `PsiUtil` functionalities and potential areas for improvement or new + features. +2. **Feasibility Study**: Analyze the technical feasibility and impact of the proposed features on the existing codebase. +3. **Define Scope**: Clearly outline what the new feature will and will not include, focusing on the `PsiUtil` class's capabilities related to PSI (Program + Structure Interface) elements in IntelliJ-based IDEs. #### Phase 2: Design - ##### Goals: + - Design the architecture and user interface (if applicable) of the new feature. - Create detailed specifications and mockups. - ##### Tasks: -1. **Technical Design**: Draft a technical design document detailing the implementation approach, including changes to methods, new method additions, and any refactoring needed. + +1. **Technical Design**: Draft a technical design document detailing the implementation approach, including changes to methods, new method additions, and any + refactoring needed. 2. **Interface Design**: If the feature involves UI changes or additions, design the user interface and interaction flow. 3. **Review and Approval**: Present the design documents to the team or stakeholders for feedback and approval. - #### Phase 3: Implementation - ##### Goals: + - Develop the code for the new feature. - Ensure the code is well-documented and adheres to coding standards. - ##### Tasks: + 1. **Setup Development Environment**: Prepare the development environment with necessary dependencies and tools. -2. **Coding**: Start coding the new features or improvements based on the design document. For instance, adding new methods to `PsiUtil` for enhanced PSI element manipulation. +2. **Coding**: Start coding the new features or improvements based on the design document. For instance, adding new methods to `PsiUtil` for enhanced PSI + element manipulation. 3. **Code Review**: Conduct code reviews with peers to ensure the code is clean, efficient, and aligns with project standards. - #### Phase 4: Testing - ##### Goals: + - Ensure the new feature works as expected and does not introduce any regressions. - Validate that the feature meets all requirements and specifications. - ##### Tasks: + 1. **Write Test Cases**: Develop comprehensive test cases covering all aspects of the new feature. 2. **Automated Testing**: Implement automated tests using a framework compatible with Kotlin projects. 3. **Manual Testing**: Perform manual testing, especially for UI-related features or complex scenarios not easily covered by automated tests. 4. **Bug Fixing**: Address any issues or bugs identified during testing. - #### Phase 5: Deployment - ##### Goals: + - Release the new feature to users. - Monitor the feature's performance and user feedback. - ##### Tasks: + 1. **Prepare Release**: Finalize the code, update documentation, and prepare the release notes. 2. **Deployment**: Deploy the new feature as part of a new release of the software. 3. **Monitor Feedback**: Collect and monitor user feedback for any issues or suggestions for further improvement. - #### Phase 6: Maintenance and Iteration - ##### Goals: + - Provide ongoing support for the new feature. - Plan and implement iterative improvements based on user feedback. - ##### Tasks: + 1. **Bug Fixes**: Continuously address any bugs or issues reported by users. 2. **Feature Enhancements**: Based on user feedback and usage data, plan and implement enhancements to the feature. 3. **Documentation Updates**: Keep the documentation up-to-date with any changes or improvements made to the feature. -This roadmap provides a structured approach to developing new features or improvements, ensuring that the end result is well-designed, thoroughly tested, and meets the users' needs. +This roadmap provides a structured approach to developing new features or improvements, ensuring that the end result is well-designed, thoroughly tested, and +meets the users' needs. # resources\sources\kt\com\github\simiacryptus\aicoder\util\TextBlockFactory.kt -The `TextBlockFactory` interface serves as a foundational component for handling text blocks within a specific context, such as parsing, generating, or analyzing text data. To further develop and enhance its capabilities, a feature development roadmap is proposed. This roadmap outlines a series of planned features and improvements aimed at expanding the utility, efficiency, and flexibility of the `TextBlockFactory` and its implementations. - +The `TextBlockFactory` interface serves as a foundational component for handling text blocks within a specific context, such as parsing, generating, or +analyzing text data. To further develop and enhance its capabilities, a feature development roadmap is proposed. This roadmap outlines a series of planned +features and improvements aimed at expanding the utility, efficiency, and flexibility of the `TextBlockFactory` and its implementations. #### Phase 1: Core Functionality Enhancements 1. **Generic Error Handling**: - - Introduce a standardized error handling mechanism for parsing and generating text blocks, ensuring robustness and reliability. + +- Introduce a standardized error handling mechanism for parsing and generating text blocks, ensuring robustness and reliability. 2. **Performance Optimization**: - - Profile and optimize the core methods (`fromString`, `toString`, `looksLike`) for better performance, especially for large text blocks. + +- Profile and optimize the core methods (`fromString`, `toString`, `looksLike`) for better performance, especially for large text blocks. 3. **Support for Rich Text Formats**: - - Extend the `TextBlockFactory` to support rich text formats (e.g., HTML, Markdown), enabling more versatile text processing capabilities. +- Extend the `TextBlockFactory` to support rich text formats (e.g., HTML, Markdown), enabling more versatile text processing capabilities. #### Phase 2: Advanced Features 4. **Asynchronous Processing**: - - Develop asynchronous versions of the `fromString` and `toString` methods to handle long-running operations without blocking the main thread, improving the responsiveness of applications. + +- Develop asynchronous versions of the `fromString` and `toString` methods to handle long-running operations without blocking the main thread, improving the + responsiveness of applications. 5. **Text Block Manipulation Utilities**: - - Introduce utility methods for common text block manipulations (e.g., trimming, splitting, merging) to facilitate more complex text processing tasks. + +- Introduce utility methods for common text block manipulations (e.g., trimming, splitting, merging) to facilitate more complex text processing tasks. 6. **Customizable Text Matching**: - - Enhance the `looksLike` method with customizable matching strategies (e.g., regex, fuzzy matching), allowing for more flexible and powerful text recognition capabilities. +- Enhance the `looksLike` method with customizable matching strategies (e.g., regex, fuzzy matching), allowing for more flexible and powerful text recognition + capabilities. #### Phase 3: Integration and Expansion 7. **Plugin Architecture for Extensions**: - - Implement a plugin architecture, enabling third-party extensions to introduce new text block types, formats, or processing algorithms seamlessly. + +- Implement a plugin architecture, enabling third-party extensions to introduce new text block types, formats, or processing algorithms seamlessly. 8. **Internationalization and Localization Support**: - - Add support for internationalization and localization, ensuring that the `TextBlockFactory` can handle text in various languages and cultural contexts effectively. + +- Add support for internationalization and localization, ensuring that the `TextBlockFactory` can handle text in various languages and cultural contexts + effectively. 9. **Machine Learning Integration**: - - Explore the integration of machine learning models for advanced text analysis and generation tasks, such as sentiment analysis, text summarization, or auto-completion. +- Explore the integration of machine learning models for advanced text analysis and generation tasks, such as sentiment analysis, text summarization, or + auto-completion. #### Phase 4: Community and Documentation 10. **Comprehensive Documentation and Examples**: - - Develop thorough documentation, including API reference, usage examples, and best practices, to assist developers in effectively utilizing the `TextBlockFactory`. + +- Develop thorough documentation, including API reference, usage examples, and best practices, to assist developers in effectively utilizing the + `TextBlockFactory`. 11. **Community Engagement and Feedback**: - - Establish channels for community engagement, such as forums or GitHub discussions, to gather feedback, prioritize feature development, and encourage contributions. + +- Establish channels for community engagement, such as forums or GitHub discussions, to gather feedback, prioritize feature development, and encourage + contributions. 12. **Tutorials and Educational Resources**: - - Create tutorials, blog posts, and video content to educate users on the capabilities of the `TextBlockFactory` and inspire innovative applications. -This roadmap is intended to guide the development of the `TextBlockFactory` interface and its ecosystem, ensuring it evolves to meet the needs of developers and remains at the forefront of text processing technology. Each phase builds upon the previous, gradually expanding the capabilities and reach of the `TextBlockFactory` while fostering a vibrant community of users and contributors. +- Create tutorials, blog posts, and video content to educate users on the capabilities of the `TextBlockFactory` and inspire innovative applications. -# resources\sources\kt\com\github\simiacryptus\aicoder\util\psi\PsiVisitorBase.kt +This roadmap is intended to guide the development of the `TextBlockFactory` interface and its ecosystem, ensuring it evolves to meet the needs of developers and +remains at the forefront of text processing technology. Each phase builds upon the previous, gradually expanding the capabilities and reach of the +`TextBlockFactory` while fostering a vibrant community of users and contributors. -Developing a feature for a software project involves a series of steps from initial conception to final release and maintenance. Below is a roadmap for developing a feature, using the provided `PsiVisitorBase` class as a context example. This class is designed to traverse and process elements in a PSI (Program Structure Interface) tree, which is a common task in plugins or tools working with code in IDEs like IntelliJ IDEA. +# resources\sources\kt\com\github\simiacryptus\aicoder\util\psi\PsiVisitorBase.kt +Developing a feature for a software project involves a series of steps from initial conception to final release and maintenance. Below is a roadmap for +developing a feature, using the provided `PsiVisitorBase` class as a context example. This class is designed to traverse and process elements in a PSI (Program +Structure Interface) tree, which is a common task in plugins or tools working with code in IDEs like IntelliJ IDEA. #### 1. Conceptualization and Planning -- **Identify the Need**: Determine the necessity for the `PsiVisitorBase` class. For instance, it might be needed for a feature that analyzes or refactors code in a specific way. -- **Define Objectives**: Clearly outline what the `PsiVisitorBase` should achieve. For example, it should provide a reusable way to traverse PSI trees and perform custom actions on each element. -- **Scope and Feasibility Study**: Assess the scope of the feature and its feasibility within the project's constraints. +- **Identify the Need**: Determine the necessity for the `PsiVisitorBase` class. For instance, it might be needed for a feature that analyzes or refactors code + in a specific way. +- **Define Objectives**: Clearly outline what the `PsiVisitorBase` should achieve. For example, it should provide a reusable way to traverse PSI trees and + perform custom actions on each element. +- **Scope and Feasibility Study**: Assess the scope of the feature and its feasibility within the project's constraints. #### 2. Design -- **Technical Design**: Detail how `PsiVisitorBase` integrates with the existing system. Design its abstract and concrete behaviors, considering how users will extend it. -- **Interface Design**: Define the public API of `PsiVisitorBase`, including its methods and their parameters. Ensure it's flexible and user-friendly for various use cases. -- **Prototype**: Optionally, create a simple prototype to validate the design concepts. +- **Technical Design**: Detail how `PsiVisitorBase` integrates with the existing system. Design its abstract and concrete behaviors, considering how users will + extend it. +- **Interface Design**: Define the public API of `PsiVisitorBase`, including its methods and their parameters. Ensure it's flexible and user-friendly for + various use cases. +- **Prototype**: Optionally, create a simple prototype to validate the design concepts. #### 3. Implementation + - **Setup Development Environment**: Ensure all necessary tools and libraries (e.g., IntelliJ Platform SDK) are available. - **Coding**: Start coding the `PsiVisitorBase` class, adhering to the design specifications. Implement the `build` method and the abstract `visit` method. - **Unit Testing**: Write unit tests for `PsiVisitorBase` to ensure each part of the class works as expected in isolation. - #### 4. Integration and Testing + - **Integration**: Integrate `PsiVisitorBase` into the larger project. This might involve updating other parts of the code to use the new class. - **Functional Testing**: Test the feature in the context of real-world scenarios to ensure it meets the requirements. - **Performance Testing**: Evaluate the performance of the `PsiVisitorBase`, especially if it's expected to process large PSI trees. - #### 5. Documentation and Release -- **Documentation**: Document the `PsiVisitorBase` class, including how to extend it and examples of its use. Ensure the documentation is clear and comprehensive. -- **Release**: Prepare the feature for release. This might involve code reviews, final testing, and merging into the main codebase. +- **Documentation**: Document the `PsiVisitorBase` class, including how to extend it and examples of its use. Ensure the documentation is clear and + comprehensive. +- **Release**: Prepare the feature for release. This might involve code reviews, final testing, and merging into the main codebase. #### 6. Maintenance and Iteration + - **Feedback Collection**: After release, collect feedback from users about the `PsiVisitorBase` and its functionality. - **Bug Fixing**: Address any bugs or issues reported by users in a timely manner. - **Feature Improvement**: Based on user feedback and further insights, plan and implement improvements to the `PsiVisitorBase`. - #### 7. Evaluation + - **Performance Evaluation**: Regularly evaluate the performance and utility of `PsiVisitorBase` in real-world scenarios. - **Feature Evolution**: Consider the need for evolving the feature to accommodate new requirements or technologies. -This roadmap provides a structured approach to developing a feature like `PsiVisitorBase`, ensuring thorough planning, execution, and maintenance for successful integration into a software project. +This roadmap provides a structured approach to developing a feature like `PsiVisitorBase`, ensuring thorough planning, execution, and maintenance for successful +integration into a software project. # resources\sources\kt\com\github\simiacryptus\aicoder\util\SimpleDiffUtil.kt -Creating a feature development roadmap for the `SimpleDiffUtil` class involves planning out enhancements, optimizations, and additional functionalities that can be integrated over time to improve its performance, usability, and feature set. Below is a proposed roadmap that outlines potential milestones and features to be developed. - +Creating a feature development roadmap for the `SimpleDiffUtil` class involves planning out enhancements, optimizations, and additional functionalities that can +be integrated over time to improve its performance, usability, and feature set. Below is a proposed roadmap that outlines potential milestones and features to +be developed. #### Phase 1: Core Functionality Enhancements + - **Improved Diff Algorithm**: Research and implement more efficient diff algorithms to improve the accuracy and performance of the patching process. - **Support for Binary Files**: Extend the utility to support diff and patch operations on binary files, not just text files. - **Parallel Processing**: Implement parallel processing for handling large files to improve performance. - #### Phase 2: Usability Improvements -- **CLI Interface**: Develop a command-line interface (CLI) for the utility, allowing users to perform diff and patch operations without integrating it into their code. -- **Error Handling and Logging**: Enhance error handling and introduce detailed logging to help users diagnose issues during the diff and patch process. -- **Configuration Options**: Allow users to configure various aspects of the utility, such as the diff algorithm sensitivity, through a configuration file or command-line arguments. +- **CLI Interface**: Develop a command-line interface (CLI) for the utility, allowing users to perform diff and patch operations without integrating it into + their code. +- **Error Handling and Logging**: Enhance error handling and introduce detailed logging to help users diagnose issues during the diff and patch process. +- **Configuration Options**: Allow users to configure various aspects of the utility, such as the diff algorithm sensitivity, through a configuration file or + command-line arguments. #### Phase 3: Advanced Features -- **Three-Way Merge**: Implement a three-way merge feature to handle conflicts more gracefully when patching files that have diverged from a common base version. -- **Patch File Generation**: Add functionality to generate patch files based on the differences between two versions of a file or directory. -- **Interactive Mode**: Introduce an interactive mode in the CLI that guides users through the diff and patch process, offering choices for handling conflicts and customizations. +- **Three-Way Merge**: Implement a three-way merge feature to handle conflicts more gracefully when patching files that have diverged from a common base + version. +- **Patch File Generation**: Add functionality to generate patch files based on the differences between two versions of a file or directory. +- **Interactive Mode**: Introduce an interactive mode in the CLI that guides users through the diff and patch process, offering choices for handling conflicts + and customizations. #### Phase 4: Integration and Expansion -- **IDE Plugins**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code to integrate the utility directly into the development workflow. -- **Version Control System Integration**: Create integrations with version control systems (VCS) like Git and SVN, allowing users to apply patches directly to their repositories. -- **Cloud Storage Support**: Enable the utility to work with files stored in cloud storage solutions like AWS S3, Google Cloud Storage, and Azure Blob Storage. +- **IDE Plugins**: Develop plugins for popular Integrated Development Environments (IDEs) like IntelliJ IDEA, Eclipse, and Visual Studio Code to integrate the + utility directly into the development workflow. +- **Version Control System Integration**: Create integrations with version control systems (VCS) like Git and SVN, allowing users to apply patches directly to + their repositories. +- **Cloud Storage Support**: Enable the utility to work with files stored in cloud storage solutions like AWS S3, Google Cloud Storage, and Azure Blob Storage. #### Phase 5: Optimization and Refinement + - **Performance Benchmarking**: Conduct thorough performance benchmarking to identify bottlenecks and optimize the codebase. - **User Feedback Loop**: Establish a feedback loop with users to gather insights on usability issues, desired features, and overall satisfaction. - **Documentation and Examples**: Expand the documentation to include more examples, use cases, and best practices for using the utility effectively. - #### Phase 6: Community and Ecosystem -- **Open Source Contributions**: Encourage community contributions by making the project open source and setting up a contribution guide, issue templates, and a code of conduct. -- **Extension API**: Design and implement an API that allows other developers to extend the utility with custom diff algorithms, file handlers, and other plugins. + +- **Open Source Contributions**: Encourage community contributions by making the project open source and setting up a contribution guide, issue templates, and a + code of conduct. +- **Extension API**: Design and implement an API that allows other developers to extend the utility with custom diff algorithms, file handlers, and other + plugins. - **Educational Resources**: Create tutorials, video demos, and blog posts to educate users on advanced features and use cases of the utility. This roadmap is a high-level plan and may evolve based on user feedback, technological advancements, and the changing needs of the project. # resources\sources\kt\com\github\simiacryptus\aicoder\util\UITools.kt - #### Feature Development Roadmap for UITools Library - ##### Phase 1: Core Functionality Enhancements + - **Task Management Improvements** - Implement a more robust task cancellation mechanism to handle long-running or stuck tasks gracefully. - Enhance the `ModalTask` and `BgTask` classes to support progress updates and allow users to see real-time progress of tasks. @@ -6229,8 +7601,8 @@ This roadmap is a high-level plan and may evolve based on user feedback, technol - Add more generic UI components such as tables, lists, and trees that support easy data binding. - Create a set of reusable dialog templates for common tasks like file selection, preferences, and input forms. - ##### Phase 2: Integration with External Services + - **OpenAI API Integration** - Implement a caching mechanism for API requests to reduce the number of calls made to the OpenAI API and improve performance. - Add support for more OpenAI API features, such as fine-tuning and embeddings. @@ -6239,8 +7611,8 @@ This roadmap is a high-level plan and may evolve based on user feedback, technol - Develop features to interact with Git directly from the UITools library, such as commit changes, view diffs, and manage branches. - Introduce a mechanism to automatically version and backup configurations or settings modified through the UI. - ##### Phase 3: User Experience and Accessibility + - **Theme and Appearance** - Implement theme support to allow users to switch between light and dark modes. - Improve the accessibility of UI components, ensuring they are usable by people with disabilities. @@ -6249,8 +7621,8 @@ This roadmap is a high-level plan and may evolve based on user feedback, technol - Add support for multiple languages, starting with major ones such as Spanish, Chinese, and French. - Implement a framework for easy addition of new languages by the community. - ##### Phase 4: Performance Optimization and Scalability + - **Concurrency and Multithreading** - Optimize existing multithreading code to improve performance and reduce the risk of deadlocks. - Implement a more efficient task scheduling algorithm to better utilize system resources. @@ -6259,8 +7631,8 @@ This roadmap is a high-level plan and may evolve based on user feedback, technol - Introduce memory optimization techniques to reduce the footprint of the library, especially in large projects. - Develop a mechanism to monitor and report memory usage within the library, helping identify memory leaks. - ##### Phase 5: Extensibility and Customization + - **Plugin Architecture** - Design and implement a plugin architecture that allows third-party developers to extend the functionality of the UITools library. - Create a marketplace or repository where users can discover and install plugins. @@ -6269,8 +7641,8 @@ This roadmap is a high-level plan and may evolve based on user feedback, technol - Allow users to customize the behavior and appearance of UI components through a settings panel. - Implement a system for saving and restoring user preferences across sessions. - ##### Phase 6: Documentation and Community Building + - **Comprehensive Documentation** - Create detailed API documentation and user guides covering all features of the library. - Develop tutorials and sample projects to help new users get started quickly. @@ -6279,8 +7651,8 @@ This roadmap is a high-level plan and may evolve based on user feedback, technol - Establish a community forum for users to share tips, ask questions, and provide feedback. - Organize regular hackathons or coding challenges to encourage community contributions to the library. - ##### Phase 7: Security and Compliance + - **Security Audits** - Conduct regular security audits to identify and fix vulnerabilities within the library. - Implement security best practices, such as secure storage of sensitive information and protection against injection attacks. @@ -6289,5 +7661,7 @@ This roadmap is a high-level plan and may evolve based on user feedback, technol - Ensure the library complies with major data protection regulations such as GDPR and CCPA. - Add features to help users manage data privacy, such as data anonymization and consent management. -This roadmap outlines a comprehensive plan for the development and enhancement of the UITools library, focusing on improving functionality, user experience, performance, and security. Each phase builds upon the previous ones, gradually expanding the library's capabilities and ensuring it meets the needs of its users. +This roadmap outlines a comprehensive plan for the development and enhancement of the UITools library, focusing on improving functionality, user experience, +performance, and security. Each phase builds upon the previous ones, gradually expanding the library's capabilities and ensuring it meets the needs of its +users. diff --git a/docs/file_metadata.template.md b/docs/file_metadata.template.md index e031f995..fb25a97e 100644 --- a/docs/file_metadata.template.md +++ b/docs/file_metadata.template.md @@ -1,31 +1,37 @@ # File Metadata Template ## Code Overview + - **Language & Frameworks:** - **Primary Purpose:** - **Brief Description:** ## Public Interface + - **Exported Functions/Classes:** - **Public Constants/Variables:** - **Types/Interfaces (if applicable):** ## Dependencies + - **External Libraries** - **Internal Code: Symbol References** ## Architecture + - **Sequence or Flow Diagrams:** Using Mermaid syntax, include sequence or flow diagram(s) to illustrate important or complex logic. (if applicable) - **Class Diagrams:** If applicable, describe (do not create) class / component / architecture diagrams needed to illustrate the context of the code ## Example Usage ## Code Analysis + - **Features:** - **Code Style Observations:** - **Code Review Feedback:** - **Potential Improvements:** ## Tags + - **Keyword Tags:** - **Key-Value Tags:** diff --git a/docs/functionality.template.md b/docs/functionality.template.md index 098935bd..33c2fda2 100644 --- a/docs/functionality.template.md +++ b/docs/functionality.template.md @@ -1,16 +1,18 @@ # Shared Functionality Analysis: [filename] ## Code Overview + - **Language & Frameworks:** - **Dependencies:** ## Common Logic -Identify and describe any logical bits that may be useful across multiple components. +Identify and describe any logical bits that may be useful across multiple components. This will generally be a list of public static functions. However, these functions may need to be extracted from existing code and refactored to be more general. ### Function 1 + - **Description:** - **Functionality:** - **Location and Accessibility:** e.g. is refactoring needed to make this an independent public static method? @@ -18,6 +20,7 @@ However, these functions may need to be extracted from existing code and refacto - **Dependencies:** ### Function 2 + - **Description:** - **Functionality:** - **Location and Accessibility:** e.g. is refactoring needed to make this an independent public static method? diff --git a/docs/manual_tests.md b/docs/manual_tests.md index 168768b9..64e75ea7 100644 --- a/docs/manual_tests.md +++ b/docs/manual_tests.md @@ -1,88 +1,92 @@ # code\CustomEditAction.kt - #### Manual Test Plan for CustomEditAction Class - ##### Objective: -To verify that the `CustomEditAction` class functions correctly, allowing users to edit code based on given instructions and configurations. +To verify that the `CustomEditAction` class functions correctly, allowing users to edit code based on given instructions and configurations. ##### Test Environment: + - IDE: IntelliJ IDEA - JDK version: Compatible version as per project requirements - Dependencies: Ensure all project dependencies are resolved, including libraries for UI and OpenAI's ChatProxy. - ##### Pre-requisites: + - The project should be correctly set up in IntelliJ IDEA. - Ensure that `AppSettingsState` is properly configured with valid settings for `temperature`, `smartModel`, and `humanLanguage`. - ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: To check if the basic functionality of editing code through virtual API is working. **Steps**: + 1. Open a project in IntelliJ. 2. Select a piece of code. 3. Trigger the `CustomEditAction`. 4. Enter a simple edit instruction, e.g., "Add a comment to this code". 5. Submit the instruction. -**Expected Result**: The code should be modified according to the instruction, with a comment added. - + **Expected Result**: The code should be modified according to the instruction, with a comment added. ###### TC2: Input Validation Test + **Objective**: To verify that the action handles empty or null instructions properly. **Steps**: + 1. Trigger the `CustomEditAction` without selecting any code. 2. Enter an empty string or just press cancel in the input dialog. -**Expected Result**: No changes should be made to the code, and no errors should occur. - + **Expected Result**: No changes should be made to the code, and no errors should occur. ###### TC3: Language Compatibility Test + **Objective**: To verify that the action correctly handles different programming languages. **Steps**: + 1. Select a piece of code written in a non-Java language, e.g., Python. 2. Trigger the `CustomEditAction`. 3. Enter an instruction relevant to the selected language, e.g., "Format according to PEP8". 4. Submit the instruction. -**Expected Result**: The code should be modified according to the instruction and should be appropriate for the language. - + **Expected Result**: The code should be modified according to the instruction and should be appropriate for the language. ###### TC4: Error Handling Test + **Objective**: To check how the action handles API failures or errors. **Steps**: + 1. Configure the `ChatProxy` to simulate an API failure. 2. Trigger the `CustomEditAction`. 3. Enter a valid instruction. -**Expected Result**: The user should be notified of the error, and no changes should be made to the code. - + **Expected Result**: The user should be notified of the error, and no changes should be made to the code. ###### TC5: History Functionality Test + **Objective**: To verify that the instruction history is updated and used correctly. **Steps**: + 1. Trigger the `CustomEditAction` multiple times with different instructions. 2. Check if the recent instructions are stored and displayed correctly in subsequent uses. -**Expected Result**: The history should correctly reflect recent instructions, and users should be able to select from them. - + **Expected Result**: The history should correctly reflect recent instructions, and users should be able to select from them. ###### TC6: Multi-language Support Test + **Objective**: To verify that the action supports editing code in different human languages. **Steps**: + 1. Change the `humanLanguage` setting in `AppSettingsState` to a non-English language. 2. Trigger the `CustomEditAction`. 3. Enter an instruction in the selected human language. -**Expected Result**: The code should be edited according to the instruction, and the interaction should be in the selected human language. - + **Expected Result**: The code should be edited according to the instruction, and the interaction should be in the selected human language. ##### Post-Test Cleanup: + - Reset any changes made to the settings during testing. - Close the project and IntelliJ IDEA. - ##### Reporting: + - Document any discrepancies from the expected results. - Capture screenshots or logs in case of failures. - Provide feedback or suggestions for improving the functionality based on test results. @@ -91,36 +95,35 @@ This manual test plan will help ensure that the `CustomEditAction` class meets i # code\DocAction.kt - #### Manual Test Plan for `DocAction` Class - ##### Objective: -To verify that the `DocAction` class correctly generates documentation comments for selected code blocks in supported programming languages. +To verify that the `DocAction` class correctly generates documentation comments for selected code blocks in supported programming languages. ##### Pre-requisites: + - IntelliJ IDEA or compatible IDE installed. - Plugin containing the `DocAction` class is installed and enabled. - Test projects in various supported languages (e.g., Java, Kotlin, Python) are set up. - ##### Test Environment: + - Operating System: [Specify OS] - IDE: IntelliJ IDEA [Specify version] - Plugin Version: [Specify version] - ##### Test Data: + - Various code snippets in supported languages. - Configurations in `AppSettingsState`. - ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: Ensure that `DocAction` generates appropriate documentation for a simple function. + - **Steps**: 1. Open a project and navigate to a source file. 2. Select a simple function or method. @@ -128,9 +131,10 @@ To verify that the `DocAction` class correctly generates documentation comments 4. Observe the generated documentation. - **Expected Result**: The documentation should be correctly added above the selected code block, matching the language's documentation style. - ###### TC2: Language Support Verification + **Objective**: Verify that `DocAction` supports all specified languages and ignores unsupported ones. + - **Steps**: 1. Repeat TC1 for each supported language (e.g., Java, Kotlin, Python). 2. Attempt to use `DocAction` on an unsupported language (e.g., plain text). @@ -138,36 +142,40 @@ To verify that the `DocAction` class correctly generates documentation comments - Documentation is generated for supported languages. - An appropriate message or no action for unsupported languages. - ###### TC3: Error Handling + **Objective**: Ensure that `DocAction` handles errors gracefully (e.g., API failures, invalid selections). + - **Steps**: 1. Simulate API failure or provide invalid code selection. 2. Trigger the `DocAction`. 3. Observe the behavior and any error messages. - **Expected Result**: The action should not crash the IDE and should display a user-friendly error message. - ###### TC4: Configuration Impact + **Objective**: Test the impact of different configurations in `AppSettingsState` on the documentation generation. + - **Steps**: 1. Modify settings in `AppSettingsState` (e.g., `humanLanguage`, `temperature`). 2. Trigger the `DocAction` on a known code block. 3. Observe and verify the changes in the generated documentation. - **Expected Result**: Changes in settings should reflect appropriately in the documentation style and content. - ###### TC5: Selection Boundary Test + **Objective**: Verify that `DocAction` correctly identifies the boundaries of code blocks. + - **Steps**: 1. Select partial code blocks, nested functions, and adjacent code blocks. 2. Trigger the `DocAction`. 3. Check if the documentation is added correctly and only within the selected boundaries. - **Expected Result**: Documentation should only apply within the exact boundaries of the selected code block. - ###### TC6: Undo/Redo Functionality + **Objective**: Ensure that the documentation addition can be undone and redone without issues. + - **Steps**: 1. Apply `DocAction` to a code block. 2. Use the IDE's undo feature. @@ -176,103 +184,110 @@ To verify that the `DocAction` class correctly generates documentation comments - The added documentation should be removed on undo. - The removed documentation should be reinstated on redo. - ##### Post-Test Cleanup: + - Revert any changes made to the test projects. - Reset configurations in `AppSettingsState` to their original values. - ##### Reporting: + - Document all test results, including any discrepancies from expected outcomes. - Report any bugs or issues to the development team for resolution. -This manual test plan will help ensure that the `DocAction` class functions correctly across different scenarios and configurations, providing reliable and accurate documentation generation in the IDE environment. +This manual test plan will help ensure that the `DocAction` class functions correctly across different scenarios and configurations, providing reliable and +accurate documentation generation in the IDE environment. # code\DescribeAction.kt - #### Manual Test Plan for `DescribeAction` Class - ##### Objective: -To verify that the `DescribeAction` class correctly generates descriptions for selected code snippets in various programming languages and integrates these descriptions as comments in the appropriate format. +To verify that the `DescribeAction` class correctly generates descriptions for selected code snippets in various programming languages and integrates these +descriptions as comments in the appropriate format. ##### Pre-requisites: + - IntelliJ IDEA or a compatible IDE installed. - Plugin containing the `DescribeAction` class is installed and enabled in the IDE. - Access to the `ChatProxy` and `AppSettingsState` configurations. - ##### Test Environment: + - Operating System: [Specify OS] - IDE Version: [Specify IDE version] - Plugin Version: [Specify Plugin version] - ##### Test Data: + - Various code snippets in supported languages (e.g., Java, Python, JavaScript). - Configurations in `AppSettingsState` for different languages and temperature settings. - ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: Ensure that the `DescribeAction` can generate a basic description for a simple code snippet. + 1. Open a project and create a file with a simple code snippet. 2. Select the code snippet. 3. Trigger the `DescribeAction`. 4. **Expected Result**: A comment is added above the selected code containing the description. - ###### TC2: Language Support Test + **Objective**: Verify that the action handles different programming languages correctly. + 1. Repeat TC1 for each supported programming language. 2. **Expected Result**: The descriptions are added in the correct comment style for each language. - ###### TC3: Multi-line Comment Test + **Objective**: Check if multi-line comments are handled correctly when the description exceeds one line. + 1. Select a code snippet that is expected to generate a multi-line description. 2. Trigger the `DescribeAction`. 3. **Expected Result**: The description should be enclosed in the appropriate multi-line comment format of the language. - ###### TC4: Error Handling Test + **Objective**: Ensure that the action handles errors gracefully (e.g., network issues, API failures). + 1. Simulate an API failure (e.g., by disconnecting from the network). 2. Trigger the `DescribeAction`. 3. **Expected Result**: An appropriate error message is displayed, and no changes are made to the code. - ###### TC5: Configuration Change Impact Test + **Objective**: Verify that changes in `AppSettingsState` affect the output as expected. + 1. Change the `humanLanguage` setting in `AppSettingsState`. 2. Trigger the `DescribeAction` on a code snippet. 3. **Expected Result**: The description should be in the newly set language. - ###### TC6: Indentation and Formatting Test + **Objective**: Confirm that the action respects the original indentation and formatting of the code. + 1. Select a code snippet with specific indentation. 2. Trigger the `DescribeAction`. 3. **Expected Result**: The description and the original code maintain their respective indentations. - ###### TC7: Performance Test + **Objective**: Ensure that the action performs within acceptable time limits for large code snippets. + 1. Select a large code snippet. 2. Trigger the `DescribeAction`. 3. **Expected Result**: The action completes within a reasonable time frame (e.g., a few seconds). - ##### Post-Test Cleanup: + - Restore any settings changed during testing. - Remove any test files or code snippets created. - ##### Reporting: + - Document any discrepancies from the expected results. - Capture screenshots or logs if applicable. - Provide feedback or suggestions for improvement based on test results. @@ -281,63 +296,65 @@ This manual test plan will help ensure that the `DescribeAction` class functions # code\CommentsAction.kt - #### Manual Test Plan for `CommentsAction` Class - ##### Objective: -To verify that the `CommentsAction` class functions correctly by adding comments to selected code based on the specified programming and human languages. +To verify that the `CommentsAction` class functions correctly by adding comments to selected code based on the specified programming and human languages. ##### Pre-requisites: + - IntelliJ IDEA or similar IDE installed. - Plugin containing the `CommentsAction` class is installed and enabled in the IDE. - Access to the `ChatProxy` service configured correctly in the plugin settings. - ##### Test Environment: + - Operating System: [Specify OS] - IDE: IntelliJ IDEA [Specify version] - Plugin Version: [Specify version] - Network: Ensure stable internet connection for `ChatProxy` service interaction. - ##### Test Data: + - Sample code snippets in supported programming languages (e.g., Java, Python, JavaScript). - Ensure various programming languages include both simple and complex code structures. - ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: Ensure that the `CommentsAction` can add comments to a simple piece of code. + 1. Open a project in the IDE. 2. Insert a simple code snippet in a supported language. 3. Select the code snippet. 4. Trigger the `CommentsAction`. 5. **Expected Result**: Comments are added to each line of the code explaining the functionality. - ###### TC2: Unsupported Language Test + **Objective**: Verify that the action does not process unsupported languages (e.g., plain text). + 1. Open a project in the IDE. 2. Insert a plain text snippet. 3. Select the text. 4. Trigger the `CommentsAction`. 5. **Expected Result**: No action is taken, and possibly an informative message is displayed indicating unsupported language. - ###### TC3: Null Selection Test + **Objective**: Ensure the action handles null or empty selections gracefully. + 1. Open a project in the IDE. 2. Ensure no text is selected or a blank file is open. 3. Trigger the `CommentsAction`. 4. **Expected Result**: No processing occurs, and an error message may be displayed indicating no selection. - ###### TC4: Network Failure Handling + **Objective**: Test how the action handles network failures during the `ChatProxy` call. + 1. Open a project in the IDE. 2. Insert a valid code snippet. 3. Select the code snippet. @@ -345,30 +362,32 @@ To verify that the `CommentsAction` class functions correctly by adding comments 5. Trigger the `CommentsAction`. 6. **Expected Result**: The action should handle the failure gracefully, possibly with an error notification about network issues. - ###### TC5: Multiple Languages and Complex Code + **Objective**: Verify that the action can handle complex code snippets across different supported languages. + 1. Open a project in the IDE. 2. Insert complex code snippets in different supported languages (e.g., nested loops, multiple functions). 3. Select each snippet one by one and trigger the `CommentsAction`. 4. **Expected Result**: Comments should accurately describe complex code structures in the appropriate human language. - ###### TC6: Configuration and Settings Test + **Objective**: Ensure that changes in settings (temperature, model) affect the output. + 1. Open settings in the IDE where `AppSettingsState` is configurable. 2. Change the `temperature` and `model` settings. 3. Insert a code snippet and select it. 4. Trigger the `CommentsAction`. 5. **Expected Result**: The output should reflect the changes in configuration, potentially altering the style or detail of comments. - ##### Post-Test Cleanup: + - Restore any settings changed during testing. - Remove any test code snippets or files created during the test. - ##### Reporting: + - Document all outcomes and, if any test fails, capture screenshots or logs if applicable. - Report the findings to the development team for further action or bug fixing. @@ -376,179 +395,210 @@ This manual test plan will help ensure that the `CommentsAction` class performs # code\ImplementStubAction.kt - #### Manual Test Plan for `ImplementStubAction` Class - ##### Objective: -To manually test the `ImplementStubAction` class to ensure it correctly interacts with the `VirtualAPI` to edit code stubs based on user selections within an IDE environment. +To manually test the `ImplementStubAction` class to ensure it correctly interacts with the `VirtualAPI` to edit code stubs based on user selections within an +IDE environment. ##### Test Environment: + - IDE (e.g., IntelliJ IDEA) - Java SDK installed - Plugin containing the `ImplementStubAction` class installed in the IDE - Access to the backend services (e.g., `ChatProxy` and `VirtualAPI`) - ##### Pre-requisites: + - The plugin is correctly installed and enabled in the IDE. - The backend services are operational and accessible. - ##### Test Cases: - ###### TC1: Language Support Validation + **Objective**: Verify that the `isLanguageSupported` method correctly identifies supported and unsupported languages. + 1. **Steps**: - - Invoke the method with various `ComputerLanguage` values including `null`, `ComputerLanguage.Text`, and other supported languages. + +- Invoke the method with various `ComputerLanguage` values including `null`, `ComputerLanguage.Text`, and other supported languages. + 2. **Expected Results**: - - The method should return `false` for `null` and `ComputerLanguage.Text`. - - The method should return `true` for other supported languages. +- The method should return `false` for `null` and `ComputerLanguage.Text`. +- The method should return `true` for other supported languages. ###### TC2: Default Selection for Code + **Objective**: Ensure that the `defaultSelection` method correctly identifies the smallest code block or the entire line if no code blocks are identified. + 1. **Steps**: - - Provide an `EditorState` with multiple code ranges and invoke the method. - - Provide an `EditorState` without code ranges and invoke the method. + +- Provide an `EditorState` with multiple code ranges and invoke the method. +- Provide an `EditorState` without code ranges and invoke the method. + 2. **Expected Results**: - - Returns the range of the smallest code block when available. - - Returns the entire line if no code blocks are present. +- Returns the range of the smallest code block when available. +- Returns the entire line if no code blocks are present. ###### TC3: Code Editing via Virtual API + **Objective**: Test the `processSelection` method's ability to send code to the `VirtualAPI` and receive edited code. + 1. **Steps**: - - Select a stub code in the editor. - - Trigger the `processSelection` method. + +- Select a stub code in the editor. +- Trigger the `processSelection` method. + 2. **Expected Results**: - - The method sends the correct parameters to the `VirtualAPI`. - - The method updates the editor with the returned `ConvertedText.code`. +- The method sends the correct parameters to the `VirtualAPI`. +- The method updates the editor with the returned `ConvertedText.code`. ###### TC4: Error Handling and Stability + **Objective**: Ensure the action handles errors gracefully when the backend service is unavailable or returns an error. + 1. **Steps**: - - Simulate backend service failure or error responses. - - Trigger the `processSelection` method. + +- Simulate backend service failure or error responses. +- Trigger the `processSelection` method. + 2. **Expected Results**: - - The method should not crash the IDE. - - Appropriate error messages or logs should be generated. +- The method should not crash the IDE. +- Appropriate error messages or logs should be generated. ###### TC5: User Interface and Integration + **Objective**: Confirm that the action integrates well with the IDE and user interactions are handled smoothly. + 1. **Steps**: - - Use the IDE's interface to trigger the action through context menus or keyboard shortcuts. - - Observe the interaction and any UI changes or prompts. + +- Use the IDE's interface to trigger the action through context menus or keyboard shortcuts. +- Observe the interaction and any UI changes or prompts. + 2. **Expected Results**: - - The action should be accessible through the expected UI elements. - - Any dialogs or prompts should display correctly and be user-friendly. +- The action should be accessible through the expected UI elements. +- Any dialogs or prompts should display correctly and be user-friendly. ##### Post-Test Cleanup: + - Reset any configurations or settings changed during testing. - Ensure no residual data or state from testing affects the normal operation of the IDE or plugin. - ##### Reporting: + - Document all test results, noting any failures or unexpected behaviors. - Report bugs or issues to the development team for resolution. -This manual test plan will help ensure that the `ImplementStubAction` class functions correctly within its intended environment and interacts properly with external services. +This manual test plan will help ensure that the `ImplementStubAction` class functions correctly within its intended environment and interacts properly with +external services. # code\InsertImplementationAction.kt - #### Manual Test Plan for `InsertImplementationAction` Class - ##### Objective: -To ensure that the `InsertImplementationAction` class functions correctly across various scenarios, including handling different programming languages, processing comments, and interacting with the virtual API to generate code implementations. +To ensure that the `InsertImplementationAction` class functions correctly across various scenarios, including handling different programming languages, +processing comments, and interacting with the virtual API to generate code implementations. ##### Test Environment: + - IDE with support for the plugin (e.g., IntelliJ IDEA). - Access to the `AppSettingsState` configurations. - A project with source code in supported languages. - ##### Prerequisites: + - Plugin is installed and enabled in the IDE. - `AppSettingsState` is configured with valid settings for `smartModel`, `chatModel`, and `temperature`. - ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: Verify that the action correctly inserts generated code based on a single line comment. + 1. Open a source file in a supported language. 2. Select a single line comment that specifies a clear implementation requirement. 3. Trigger the `InsertImplementationAction`. -4. **Expected Result**: - - The action communicates with the virtual API. - - Generated code is inserted correctly below the comment. +4. **Expected Result**: +- The action communicates with the virtual API. +- Generated code is inserted correctly below the comment. ###### TC2: Multi-line Comment Test + **Objective**: Verify that the action handles multi-line comments correctly. + 1. Open a source file in a supported language. 2. Select a multi-line comment with a detailed specification. 3. Trigger the `InsertImplementationAction`. 4. **Expected Result**: - - The action processes the entire comment as a single specification. - - Appropriate code is generated and inserted. +- The action processes the entire comment as a single specification. +- Appropriate code is generated and inserted. ###### TC3: No Comment Selected Test + **Objective**: Verify behavior when no comment is selected. + 1. Open a source file in a supported language. 2. Place the cursor in a code block without any nearby comments. 3. Trigger the `InsertImplementationAction`. 4. **Expected Result**: - - No action is taken, or a user-friendly message is displayed indicating no specification found. +- No action is taken, or a user-friendly message is displayed indicating no specification found. ###### TC4: Unsupported Language Test + **Objective**: Verify that the action does not proceed with unsupported languages. + 1. Open a source file in an unsupported language (e.g., plain text or Markdown). 2. Select any portion of text. 3. Trigger the `InsertImplementationAction`. 4. **Expected Result**: - - The action should not proceed. - - A message indicates that the language is not supported. +- The action should not proceed. +- A message indicates that the language is not supported. ###### TC5: Error Handling Test + **Objective**: Verify that the action handles API errors gracefully. + 1. Configure the `AppSettingsState` with an invalid `chatModel`. 2. Open a source file in a supported language. 3. Select a comment and trigger the `InsertImplementationAction`. 4. **Expected Result**: - - The action should handle the error without crashing. - - A user-friendly error message is displayed. +- The action should handle the error without crashing. +- A user-friendly error message is displayed. ###### TC6: Large Specification Test + **Objective**: Verify that the action handles large specifications without performance degradation. + 1. Open a source file in a supported language. 2. Select a very long comment that spans multiple lines and includes complex specifications. 3. Trigger the `InsertImplementationAction`. 4. **Expected Result**: - - The action processes the comment efficiently. - - Code is generated and inserted without significant delay. +- The action processes the comment efficiently. +- Code is generated and inserted without significant delay. ##### Reporting: + - Document the outcome of each test case. - Capture any discrepancies from the expected results. - Report bugs or enhancements to the development team. - ##### Cleanup: + - Revert any changes made to the source files during testing. - Restore original `AppSettingsState` configurations if modified. @@ -556,761 +606,855 @@ This manual test plan will help ensure that the `InsertImplementationAction` cla # code\PasteAction.kt - #### Manual Test Plan for `PasteAction` Class - ##### Objective: -To verify that the `PasteAction` class functions correctly by pasting and converting clipboard content into a specified programming language using a virtual API. +To verify that the `PasteAction` class functions correctly by pasting and converting clipboard content into a specified programming language using a virtual +API. ##### Prerequisites: + - IntelliJ IDEA or a similar IDE installed. - Plugin containing the `PasteAction` class is installed and enabled. - Clipboard operations are permitted on the test machine. - ##### Test Environment: + - Operating System: [Specify OS] - IDE: IntelliJ IDEA [Specify version] - Java Version: [Specify version] - Dependencies: Ensure all dependencies are correctly configured, including `ChatProxy` and `VirtualAPI`. - ##### Test Data: + - Various strings representing code snippets in different languages. - Non-code text to test language detection and rejection. - ##### Test Cases: - ###### TC1: Clipboard Contains Valid Code Snippet + **Objective**: Verify that the action correctly pastes and converts a valid code snippet from the clipboard. + 1. Copy a valid code snippet (e.g., Java code) to the clipboard. 2. Trigger the `PasteAction`. 3. Verify that the output is the expected converted code in the target language specified in the `SelectionState`. - ###### TC2: Clipboard Contains Plain Text + **Objective**: Verify that the action handles plain text (non-code) appropriately. + 1. Copy plain text (e.g., "Hello World") to the clipboard. 2. Trigger the `PasteAction`. 3. Verify that the action either converts the text or handles it as unsupported, based on implementation. - ###### TC3: Unsupported Language Conversion + **Objective**: Verify that the action handles conversion requests for unsupported languages. + 1. Set the target language in `SelectionState` to an unsupported language. 2. Copy a valid code snippet to the clipboard. 3. Trigger the `PasteAction`. 4. Verify that the action handles the unsupported language gracefully (e.g., error message, no conversion). - ###### TC4: Clipboard is Empty + **Objective**: Verify that the action handles an empty clipboard correctly. + 1. Ensure the clipboard is empty. 2. Trigger the `PasteAction`. 3. Verify that the action does not proceed with conversion and handles the situation appropriately. - ###### TC5: Error Handling in API + **Objective**: Verify that the action handles API errors gracefully. + 1. Simulate an API failure (e.g., network error, API returns error). 2. Copy a valid code snippet to the clipboard. 3. Trigger the `PasteAction`. 4. Verify that the action handles the error gracefully and provides a user-friendly message. - ###### TC6: Check Language Support + **Objective**: Verify that the action correctly identifies supported and unsupported languages. + 1. Iterate through a list of known supported and unsupported languages. 2. For each language, set it in `SelectionState` and copy a corresponding code snippet to the clipboard. 3. Trigger the `PasteAction`. 4. Verify that the action correctly identifies whether the language is supported. - ##### Reporting: + - Document the results of each test case. - Include details such as the input, expected outcome, actual outcome, and any discrepancies. - Report any bugs or issues to the development team for resolution. - ##### Cleanup: + - Reset any settings or configurations changed during testing. - Clear the clipboard to avoid any data leakage. -This manual test plan will help ensure that the `PasteAction` class behaves as expected under various conditions and handles different types of clipboard content appropriately. +This manual test plan will help ensure that the `PasteAction` class behaves as expected under various conditions and handles different types of clipboard +content appropriately. # code\RecentCodeEditsAction.kt - #### Manual Test Plan for RecentCodeEditsAction Class - ##### Objective: -To ensure that the `RecentCodeEditsAction` class functions correctly, providing a dynamic list of recent custom code edits in the IDE, and enabling or disabling based on the context. +To ensure that the `RecentCodeEditsAction` class functions correctly, providing a dynamic list of recent custom code edits in the IDE, and enabling or disabling +based on the context. ##### Pre-requisites: + - IntelliJ IDEA or compatible IDE installed. - Plugin containing the `RecentCodeEditsAction` class installed and enabled. - `AppSettingsState` configured with a mock or real data source for recent commands. - ##### Test Environment: + - Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur] - IDE Version: [Specify version - e.g., IntelliJ IDEA 2021.3] - Java Version: [Specify version - e.g., Java 11] - ##### Test Data: + - Sample recent commands in `AppSettingsState`: - "Refactor variable names" - "Optimize imports" - "Format code" - "Add documentation comments" - ##### Test Cases: - ###### TC1: Visibility and Enablement of Action + **Objective**: Verify that the action is visible and enabled only when appropriate. **Steps**: + 1. Open a project in the IDE. 2. Select a text file and right-click to open the context menu. 3. Observe if the `RecentCodeEditsAction` is visible and enabled. 4. Repeat steps 2-3 with a source code file (e.g., a Java file). **Expected Results**: + - The action should be invisible and disabled for text files. - The action should be visible and enabled for source code files. - ###### TC2: Correct Listing of Recent Edits + **Objective**: Verify that the action correctly lists recent code edits. **Steps**: + 1. Trigger the `RecentCodeEditsAction` by selecting it from the context menu in a source code file. 2. Observe the list of actions displayed. **Expected Results**: -- The list should correctly display all recent edits stored in `AppSettingsState`, formatted as specified (e.g., "_1: Refactor variable names"). +- The list should correctly display all recent edits stored in `AppSettingsState`, formatted as specified (e.g., "_1: Refactor variable names"). ###### TC3: Execution of a Recent Edit Command + **Objective**: Verify that selecting a recent edit command executes it correctly. **Steps**: + 1. From the list of recent edits, select an action (e.g., "_1: Refactor variable names"). 2. Observe the behavior in the IDE (you may need to simulate or mock the execution effect). **Expected Results**: -- The selected action should execute appropriately (e.g., refactoring process starts). +- The selected action should execute appropriately (e.g., refactoring process starts). ###### TC4: Dynamic Update of Recent Edits List + **Objective**: Verify that the list updates dynamically with new edits. **Steps**: + 1. Add a new edit command to `AppSettingsState`. 2. Reopen or refresh the `RecentCodeEditsAction` list. 3. Check if the new command appears in the list. **Expected Results**: -- The new command should appear in the list without requiring a restart of the IDE. +- The new command should appear in the list without requiring a restart of the IDE. ##### Post-Test Cleanup: -- Reset any changes made to `AppSettingsState` or other configurations during testing. +- Reset any changes made to `AppSettingsState` or other configurations during testing. ##### Reporting: + - Document any discrepancies from expected results. - Capture screenshots or logs if applicable. - Provide feedback or suggestions for improvements based on test outcomes. -This manual test plan aims to cover basic functional aspects of the `RecentCodeEditsAction` class. Adjustments may be necessary based on actual application behavior and additional requirements. +This manual test plan aims to cover basic functional aspects of the `RecentCodeEditsAction` class. Adjustments may be necessary based on actual application +behavior and additional requirements. # code\RenameVariablesAction.kt - #### Manual Test Plan for `RenameVariablesAction` Class - ##### Objective -To manually test the `RenameVariablesAction` class to ensure that it correctly suggests and applies variable name changes in code based on AI recommendations. +To manually test the `RenameVariablesAction` class to ensure that it correctly suggests and applies variable name changes in code based on AI recommendations. ##### Test Environment + - IDE: IntelliJ IDEA - Project setup with necessary dependencies and plugin configurations. - Access to `AppSettingsState` and `ChatProxy` configurations. - ##### Pre-requisites + - The plugin containing `RenameVariablesAction` is installed and enabled in IntelliJ IDEA. - The user has opened a project with source code files in supported languages. - ##### Test Cases - ###### TC1: Basic Functionality Test + **Objective**: Verify that the action suggests and applies renames correctly for a simple case. + 1. **Steps**: - - Open a source file with a few variables. - - Highlight a variable name. - - Trigger the `RenameVariablesAction`. - - Select all suggested renames in the dialog. - - Apply the changes. + +- Open a source file with a few variables. +- Highlight a variable name. +- Trigger the `RenameVariablesAction`. +- Select all suggested renames in the dialog. +- Apply the changes. + 2. **Expected Result**: - - The variable names in the code are renamed as suggested by the AI. - - No syntax errors or unresolved references should occur due to renaming. +- The variable names in the code are renamed as suggested by the AI. +- No syntax errors or unresolved references should occur due to renaming. ###### TC2: No Selection Test + **Objective**: Verify the behavior when no text is selected. + 1. **Steps**: - - Open a source file. - - Ensure no text is selected. - - Trigger the `RenameVariablesAction`. + +- Open a source file. +- Ensure no text is selected. +- Trigger the `RenameVariablesAction`. + 2. **Expected Result**: - - An appropriate message indicating no selection or no operation should be displayed. +- An appropriate message indicating no selection or no operation should be displayed. ###### TC3: Unsupported Language Test + **Objective**: Verify that the action does not proceed in unsupported languages. + 1. **Steps**: - - Open a text file or a file of an unsupported language. - - Select some text. - - Trigger the `RenameVariablesAction`. + +- Open a text file or a file of an unsupported language. +- Select some text. +- Trigger the `RenameVariablesAction`. + 2. **Expected Result**: - - The action should not proceed, possibly showing a message that the language is unsupported. +- The action should not proceed, possibly showing a message that the language is unsupported. ###### TC4: Multiple Suggestions Test + **Objective**: Verify that the action handles multiple suggestions correctly. + 1. **Steps**: - - Open a source file with multiple variables. - - Highlight a block of code containing multiple variable names. - - Trigger the `RenameVariablesAction`. - - Choose only a subset of the suggested renames. - - Apply the changes. + +- Open a source file with multiple variables. +- Highlight a block of code containing multiple variable names. +- Trigger the `RenameVariablesAction`. +- Choose only a subset of the suggested renames. +- Apply the changes. + 2. **Expected Result**: - - Only the selected variable names should be renamed. - - The code should remain functional with no unresolved references. +- Only the selected variable names should be renamed. +- The code should remain functional with no unresolved references. ###### TC5: Cancel Operation Test + **Objective**: Verify that cancelling the rename operation leaves the code unchanged. + 1. **Steps**: - - Open a source file. - - Select a variable name. - - Trigger the `RenameVariablesAction`. - - When the rename suggestions dialog appears, cancel the operation. + +- Open a source file. +- Select a variable name. +- Trigger the `RenameVariablesAction`. +- When the rename suggestions dialog appears, cancel the operation. + 2. **Expected Result**: - - No changes should be made to the code. +- No changes should be made to the code. ###### TC6: Error Handling Test + **Objective**: Verify that the system handles errors gracefully (e.g., API failures, network issues). + 1. **Steps**: - - Simulate an API failure or network issue (e.g., by temporarily modifying the `ChatProxy` settings to an invalid state). - - Open a source file and select a variable name. - - Trigger the `RenameVariablesAction`. + +- Simulate an API failure or network issue (e.g., by temporarily modifying the `ChatProxy` settings to an invalid state). +- Open a source file and select a variable name. +- Trigger the `RenameVariablesAction`. + 2. **Expected Result**: - - An error message should be displayed, and no changes should be made to the code. +- An error message should be displayed, and no changes should be made to the code. ##### Post-Test Cleanup + - Restore any settings or configurations changed during testing. - Close all open files and projects in the IDE. - ##### Reporting + - Document the results of each test case, including any discrepancies from expected outcomes. - Report any bugs or issues to the development team for resolution. # dev\AppServer.kt - #### Manual Test Plan for AppServer Class - ##### Objective: -To verify the functionality and robustness of the `AppServer` class, ensuring it can handle web application contexts, manage WebSocket connections, and respond appropriately to user interactions and system events. +To verify the functionality and robustness of the `AppServer` class, ensuring it can handle web application contexts, manage WebSocket connections, and respond +appropriately to user interactions and system events. ##### Test Environment: + - IDE: IntelliJ IDEA - JDK version: Java 11 or higher - Operating System: Windows/Linux/MacOS - Required Libraries: Jetty server, SLF4J, WebSocket API - ##### Test Data: + - Local server name: "localhost" - Port: 8080 - Sample paths for web applications: "/chat", "/info" - Sample `ChatServer` instances - ##### Pre-conditions: + - Ensure that the required Java version and libraries are installed and configured. - Ensure no other services are running on the test port (8080). - ##### Test Cases: 1. **Initialization Test** - - **Objective**: Verify that the server initializes correctly with the specified local name and port. - - **Steps**: - 1. Instantiate `AppServer` with "localhost" and 8080. - 2. Call `start()` method. - - **Expected Result**: Server starts without errors, and logs indicate initialization at the specified address and port. + +- **Objective**: Verify that the server initializes correctly with the specified local name and port. +- **Steps**: + 1. Instantiate `AppServer` with "localhost" and 8080. + 2. Call `start()` method. +- **Expected Result**: Server starts without errors, and logs indicate initialization at the specified address and port. 2. **Add Application Test** - - **Objective**: Verify that applications can be added dynamically and are accessible. - - **Steps**: - 1. Start the server. - 2. Create a `ChatServer` instance and add it using `addApp("/chat", chatServerInstance)`. - 3. Access `localhost:8080/chat`. - - **Expected Result**: - - The server should restart with the new context. - - The chat application should be accessible and functional at the specified path. + +- **Objective**: Verify that applications can be added dynamically and are accessible. +- **Steps**: + 1. Start the server. + 2. Create a `ChatServer` instance and add it using `addApp("/chat", chatServerInstance)`. + 3. Access `localhost:8080/chat`. +- **Expected Result**: + - The server should restart with the new context. + - The chat application should be accessible and functional at the specified path. 3. **Server Restart on New App Addition** - - **Objective**: Ensure the server restarts correctly when a new application is added. - - **Steps**: - 1. Start the server. - 2. Add a new `ChatServer` application. - 3. Monitor logs for restart messages. - - **Expected Result**: Logs should indicate that the server was stopped and restarted successfully. + +- **Objective**: Ensure the server restarts correctly when a new application is added. +- **Steps**: + 1. Start the server. + 2. Add a new `ChatServer` application. + 3. Monitor logs for restart messages. +- **Expected Result**: Logs should indicate that the server was stopped and restarted successfully. 4. **Concurrency Test** - - **Objective**: Verify that the server can handle multiple requests simultaneously. - - **Steps**: - 1. Start the server. - 2. Simultaneously access multiple paths ("/chat", "/info") from different clients. - - **Expected Result**: All clients should receive correct responses without any delay or errors. + +- **Objective**: Verify that the server can handle multiple requests simultaneously. +- **Steps**: + 1. Start the server. + 2. Simultaneously access multiple paths ("/chat", "/info") from different clients. +- **Expected Result**: All clients should receive correct responses without any delay or errors. 5. **Error Handling Test** - - **Objective**: Verify that the server handles errors gracefully. - - **Steps**: - 1. Start the server. - 2. Simulate an error scenario (e.g., add an app with invalid configuration). - 3. Check the response and logs. - - **Expected Result**: Appropriate error messages are logged, and the server continues to run other contexts correctly. + +- **Objective**: Verify that the server handles errors gracefully. +- **Steps**: + 1. Start the server. + 2. Simulate an error scenario (e.g., add an app with invalid configuration). + 3. Check the response and logs. +- **Expected Result**: Appropriate error messages are logged, and the server continues to run other contexts correctly. 6. **Server Stop Test** - - **Objective**: Ensure the server stops cleanly on command. - - **Steps**: - 1. Start the server. - 2. Call `stop()` from the `AppServer.Companion` object. - - **Expected Result**: Server stops without errors, and logs indicate a clean shutdown. + +- **Objective**: Ensure the server stops cleanly on command. +- **Steps**: + 1. Start the server. + 2. Call `stop()` from the `AppServer.Companion` object. +- **Expected Result**: Server stops without errors, and logs indicate a clean shutdown. 7. **Resource Leak Test** - - **Objective**: Ensure there are no resource leaks (threads, file handles, sockets) after server operations. - - **Steps**: - 1. Start and stop the server multiple times. - 2. Monitor system resources. - - **Expected Result**: No increase in resource usage over time, indicating no leaks. +- **Objective**: Ensure there are no resource leaks (threads, file handles, sockets) after server operations. +- **Steps**: + 1. Start and stop the server multiple times. + 2. Monitor system resources. +- **Expected Result**: No increase in resource usage over time, indicating no leaks. ##### Post-conditions: -- Server should be stopped, and all resources should be released. +- Server should be stopped, and all resources should be released. ##### Reporting: + - Document all test results, including any discrepancies from expected outcomes. - Log all error messages and stack traces for failed tests. - ##### Cleanup: + - Ensure all instances of `AppServer` are terminated. - Release any ports and system resources used during testing. -This manual test plan will help ensure that the `AppServer` class functions as expected under various conditions and handles errors and multiple simultaneous requests efficiently. +This manual test plan will help ensure that the `AppServer` class functions as expected under various conditions and handles errors and multiple simultaneous +requests efficiently. # dev\PrintTreeAction.kt - #### Manual Test Plan for PrintTreeAction - ##### Objective: -To verify that the `PrintTreeAction` in the IntelliJ plugin correctly prints the tree structure of a PsiFile when triggered. +To verify that the `PrintTreeAction` in the IntelliJ plugin correctly prints the tree structure of a PsiFile when triggered. ##### Pre-requisites: + 1. IntelliJ IDEA must be installed. 2. The plugin containing `PrintTreeAction` must be installed and enabled in IntelliJ IDEA. 3. `devActions` setting must be enabled in the plugin's `AppSettingsState`. - ##### Test Environment: + - Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur, etc.] - IntelliJ IDEA Version: [Specify version - e.g., 2021.2] - Plugin Version: [Specify version] - ##### Test Data: -- Various PsiFiles with different complexities and structures. +- Various PsiFiles with different complexities and structures. ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: Ensure that the action prints the tree structure for a simple PsiFile. **Steps**: + 1. Open a simple project in IntelliJ. 2. Open a file (e.g., a simple Java class). 3. Right-click in the editor window and select "PrintTreeAction" from the context menu. -**Expected Result**: -- The tree structure of the PsiFile is printed in the log. + **Expected Result**: +- The tree structure of the PsiFile is printed in the log. ###### TC2: Action Visibility Test + **Objective**: Verify that the action is only visible when `devActions` is enabled. **Steps**: + 1. Disable `devActions` in the plugin settings. 2. Right-click in the editor window. -**Expected Result**: -- The "PrintTreeAction" should not be visible in the context menu. + **Expected Result**: +- The "PrintTreeAction" should not be visible in the context menu. ###### TC3: Action Enabled Test with `devActions` Enabled + **Objective**: Confirm that the action is enabled when `devActions` is true. **Steps**: + 1. Ensure `devActions` is enabled. 2. Right-click in the editor window and observe the "PrintTreeAction". -**Expected Result**: -- The action should be enabled and selectable. + **Expected Result**: +- The action should be enabled and selectable. ###### TC4: Large File Test + **Objective**: Test the action's performance and correctness on a large PsiFile. **Steps**: + 1. Open a large file (e.g., a file with thousands of lines of code). 2. Trigger the "PrintTreeAction". -**Expected Result**: -- The tree structure is printed in the log without crashing or significant performance degradation. + **Expected Result**: +- The tree structure is printed in the log without crashing or significant performance degradation. ###### TC5: Error Handling Test + **Objective**: Ensure the action handles null PsiFile gracefully. **Steps**: + 1. Open an empty editor window (no file open). 2. Try to trigger the "PrintTreeAction". -**Expected Result**: -- An appropriate error message is logged, indicating no file is open or the file is not valid. + **Expected Result**: +- An appropriate error message is logged, indicating no file is open or the file is not valid. ###### TC6: Logging Verification Test + **Objective**: Verify that the output is logged correctly. **Steps**: + 1. Trigger the action with any open file. 2. Check the IntelliJ log for the output. -**Expected Result**: -- The output in the log matches the expected tree structure of the PsiFile. + **Expected Result**: +- The output in the log matches the expected tree structure of the PsiFile. ##### Post-Test Cleanup: + - Reset any settings changed during testing. - Close any files or projects opened during testing. - ##### Reporting: + - Document any discrepancies from the expected results. - Capture log outputs and any error messages for failed test cases. - Provide feedback or suggestions for improving the action based on test results. -This manual test plan will help ensure that the `PrintTreeAction` functions correctly across different scenarios and setups, providing confidence in its reliability and effectiveness. +This manual test plan will help ensure that the `PrintTreeAction` functions correctly across different scenarios and setups, providing confidence in its +reliability and effectiveness. # generic\GenerateRelatedFileAction.kt - #### Manual Test Plan for CreateFileFromTemplateAction Class - ##### Objective: -To verify that the `CreateFileFromTemplateAction` class functions correctly across various scenarios, including file generation based on user directives and handling of file paths. +To verify that the `CreateFileFromTemplateAction` class functions correctly across various scenarios, including file generation based on user directives and +handling of file paths. ##### Test Environment Setup: + - Install IntelliJ IDEA or compatible IDE. - Ensure the plugin containing `CreateFileFromTemplateAction` is installed and enabled. - Configure necessary dependencies and environment as per the project requirements. - ##### Test Data: + - Various project files with different content and structures. - Directives for file generation (e.g., "Create test cases", "Refactor code to new standards"). - ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: Verify that the action generates a new file correctly based on a simple directive. + 1. **Preconditions**: Open a project with at least one non-directory file. 2. **Test Steps**: - - Right-click on a file and select "Create Analogue File". - - Enter the directive: "Create test cases". - - Execute the action. + +- Right-click on a file and select "Create Analogue File". +- Enter the directive: "Create test cases". +- Execute the action. + 3. **Expected Results**: - - A new file is created in the same directory as the original. - - The new file contains content relevant to the directive. +- A new file is created in the same directory as the original. +- The new file contains content relevant to the directive. ###### TC2: Directory Selection Handling + **Objective**: Ensure the action is disabled when a directory is selected. + 1. **Preconditions**: Open a project and select a directory. 2. **Test Steps**: - - Right-click on the directory and observe the available actions. + +- Right-click on the directory and observe the available actions. + 3. **Expected Results**: - - The "Create Analogue File" action should be disabled or not visible. +- The "Create Analogue File" action should be disabled or not visible. ###### TC3: Non-existent Path Handling + **Objective**: Verify the action's response when the generated file path does not exist. + 1. **Preconditions**: Open a project with at least one file. 2. **Test Steps**: - - Right-click on a file and select "Create Analogue File". - - Enter a directive that implies saving to a non-existent path. - - Execute the action. + +- Right-click on a file and select "Create Analogue File". +- Enter a directive that implies saving to a non-existent path. +- Execute the action. + 3. **Expected Results**: - - Directories along the path are created as needed. - - The file is successfully created at the specified path. +- Directories along the path are created as needed. +- The file is successfully created at the specified path. ###### TC4: File Overwrite Handling + **Objective**: Test how the action handles scenarios where the file already exists. + 1. **Preconditions**: A file already exists at the target path. 2. **Test Steps**: - - Right-click on a file and select "Create Analogue File". - - Enter a directive that results in a file path where a file already exists. - - Execute the action. + +- Right-click on a file and select "Create Analogue File". +- Enter a directive that results in a file path where a file already exists. +- Execute the action. + 3. **Expected Results**: - - The action does not overwrite the existing file but creates a new file with a modified name to avoid duplication. +- The action does not overwrite the existing file but creates a new file with a modified name to avoid duplication. ###### TC5: Error Handling and Messages + **Objective**: Ensure that appropriate error messages are displayed for various failure scenarios. + 1. **Preconditions**: Open a project. 2. **Test Steps**: - - Induce different error scenarios like API failures, permission issues, etc. - - Observe the error handling and messages displayed. + +- Induce different error scenarios like API failures, permission issues, etc. +- Observe the error handling and messages displayed. + 3. **Expected Results**: - - Relevant and user-friendly error messages are displayed. - - The system handles exceptions gracefully without crashing. +- Relevant and user-friendly error messages are displayed. +- The system handles exceptions gracefully without crashing. ###### TC6: Performance Test + **Objective**: Verify that the action performs well even with large files or under load. + 1. **Preconditions**: Open a project with large files. 2. **Test Steps**: - - Execute the action on large files multiple times. - - Monitor the response time and resource usage. + +- Execute the action on large files multiple times. +- Monitor the response time and resource usage. + 3. **Expected Results**: - - The action completes within a reasonable time. - - No significant degradation in IDE performance. +- The action completes within a reasonable time. +- No significant degradation in IDE performance. ##### Post-Test Cleanup: + - Remove any files or configurations added specifically for testing. - Restore any settings changed during the test. - ##### Reporting: + - Document all test results, including any discrepancies from expected outcomes. - Report bugs or enhancement requests based on the findings. -This manual test plan ensures comprehensive coverage of the `CreateFileFromTemplateAction` functionality and helps maintain high quality and reliability of the feature. +This manual test plan ensures comprehensive coverage of the `CreateFileFromTemplateAction` functionality and helps maintain high quality and reliability of the +feature. # generic\AppendTextWithChatAction.kt - #### Manual Test Plan for `AppendTextWithChatAction` Class - ##### Objective: -To verify that the `AppendTextWithChatAction` class correctly appends text to the user's selected text using the AI model's response. +To verify that the `AppendTextWithChatAction` class correctly appends text to the user's selected text using the AI model's response. ##### Pre-requisites: + - IntelliJ IDEA or any compatible IDE installed. - Access to the project's repository and necessary permissions to run and test the code. - Ensure the AI model and API are properly configured and accessible. - ##### Test Environment: + - Development or testing environment with the project setup. - Ensure all dependencies are correctly configured in the project. - ##### Test Data: + - Various strings of text to use as user selections. - Configurations in `AppSettingsState` for different scenarios (e.g., different temperatures, models). - ##### Test Cases: - ###### TC1: Basic Append Functionality + **Objective**: To test if the system appends any text to the selected text. **Steps**: + 1. Open a file in the IDE and select a string of text. 2. Trigger the `AppendTextWithChatAction`. 3. Observe the output in the IDE or the designated output area. -**Expected Result**: The selected text should have additional text appended at the end. - + **Expected Result**: The selected text should have additional text appended at the end. ###### TC2: No Selected Text + **Objective**: To verify the behavior when no text is selected. **Steps**: + 1. Ensure no text is selected in the IDE. 2. Trigger the `AppendTextWithChatAction`. 3. Observe the output or any error messages. -**Expected Result**: No changes should occur, or a user-friendly message should be displayed. - + **Expected Result**: No changes should occur, or a user-friendly message should be displayed. ###### TC3: API Response Handling + **Objective**: To test the handling of different API responses, including errors. **Steps**: + 1. Mock different responses from the API, including success, failure, and edge cases like empty strings or null. 2. Select a string of text and trigger the `AppendTextWithChatAction` for each mocked response. 3. Observe how the application handles each response. -**Expected Result**: The application should handle each scenario gracefully, appending text correctly on success, and showing appropriate messages or handling on failures. - + **Expected Result**: The application should handle each scenario gracefully, appending text correctly on success, and showing appropriate messages or + handling on failures. ###### TC4: Long Text Selections + **Objective**: To test the system's performance with very long text selections. **Steps**: + 1. Select a very long string of text in the IDE. 2. Trigger the `AppendTextWithChatAction`. 3. Observe the performance and any potential lag or failure. -**Expected Result**: The action should complete within a reasonable time without errors. - + **Expected Result**: The action should complete within a reasonable time without errors. ###### TC5: Special Characters and Formats + **Objective**: To verify that the action handles text with special characters and formats correctly. **Steps**: + 1. Select text containing special characters (e.g., emojis, symbols) or formats (e.g., code snippets, markdown). 2. Trigger the `AppendTextWithChatAction`. 3. Check if the appended text respects the original format and characters. -**Expected Result**: The appended text should correctly include and display special characters and formats. - + **Expected Result**: The appended text should correctly include and display special characters and formats. ###### TC6: Configuration Changes + **Objective**: To test the system's response to changes in configuration settings. **Steps**: + 1. Change the settings in `AppSettingsState` (e.g., different AI models, temperature settings). 2. Select a string of text and trigger the `AppendTextWithChatAction`. 3. Observe how the changes affect the output. -**Expected Result**: Outputs should vary according to the configuration, reflecting the changes accurately. - + **Expected Result**: Outputs should vary according to the configuration, reflecting the changes accurately. ##### Post-Test Cleanup: + - Reset any configurations changed during testing to their original states. - Close and clean up any resources used during the test. - ##### Reporting: + - Document any discrepancies from the expected results. - Provide feedback and suggestions based on the test outcomes. -This manual test plan will help ensure that the `AppendTextWithChatAction` class functions correctly across various scenarios and handles both expected and edge cases gracefully. +This manual test plan will help ensure that the `AppendTextWithChatAction` class functions correctly across various scenarios and handles both expected and edge +cases gracefully. # generic\CodeChatAction.kt - #### Manual Test Plan for CodeChatAction - ##### Objective: -To manually test the `CodeChatAction` class to ensure it correctly initializes and handles a code chat session within an IDE environment. +To manually test the `CodeChatAction` class to ensure it correctly initializes and handles a code chat session within an IDE environment. ##### Pre-requisites: + 1. IntelliJ IDEA or a similar IDE installed. 2. Plugin containing the `CodeChatAction` class installed in the IDE. 3. Necessary permissions to access and modify files and to open web browsers from the IDE. - ##### Test Environment: + - Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur] - IDE Version: [Specify IDE version] - Plugin Version: [Specify plugin version] - Network Configuration: Ensure internet access for server communication. - ##### Test Data: -- Sample code files in various supported languages (e.g., Java, Python, C++). +- Sample code files in various supported languages (e.g., Java, Python, C++). ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: Verify that the action is triggered correctly and opens a chat session in the default browser. + 1. Open a project and select a file. 2. Trigger the `CodeChatAction`. 3. **Expected Result**: - - A new browser tab opens with the chat interface. - - The chat session corresponds to the selected file and language. +- A new browser tab opens with the chat interface. +- The chat session corresponds to the selected file and language. ###### TC2: Null Editor Handling + **Objective**: Ensure the action handles null editor instances gracefully. + 1. Trigger the `CodeChatAction` without opening any file. 2. **Expected Result**: - - No action is taken. - - No errors or crashes occur. +- No action is taken. +- No errors or crashes occur. ###### TC3: Unsupported Language Handling + **Objective**: Verify that the action handles files with unsupported languages gracefully. + 1. Open a file with an unsupported language or plain text. 2. Trigger the `CodeChatAction`. 3. **Expected Result**: - - No chat session is initiated. - - Appropriate user feedback is provided (e.g., a notification). +- No chat session is initiated. +- Appropriate user feedback is provided (e.g., a notification). ###### TC4: Session Initialization + **Objective**: Check if a new session is correctly initialized with valid parameters. + 1. Open a supported file and select some text. 2. Trigger the `CodeChatAction`. 3. **Expected Result**: - - A new session is created with the correct language and selected text. - - The session ID is correctly appended to the URL. +- A new session is created with the correct language and selected text. +- The session ID is correctly appended to the URL. ###### TC5: Error Handling in Browser Opening + **Objective**: Ensure that errors during browser opening are logged without crashing the application. + 1. Temporarily modify system settings to prevent the IDE from opening a browser. 2. Trigger the `CodeChatAction`. 3. **Expected Result**: - - An error is logged. - - The application does not crash. +- An error is logged. +- The application does not crash. ###### TC6: Multiple Sessions Handling + **Objective**: Verify that multiple sessions can be handled simultaneously without interference. + 1. Open multiple files in different tabs. 2. Trigger the `CodeChatAction` in each tab sequentially. 3. **Expected Result**: - - Each file opens its own chat session in a new browser tab. - - Sessions do not interfere with each other. +- Each file opens its own chat session in a new browser tab. +- Sessions do not interfere with each other. ##### Post-Test Cleanup: + - Close all opened browser tabs and IDE projects. - Restore any modified system settings. - ##### Reporting: + - Document all outcomes and any deviations from expected results. - Capture logs and screenshots for failed test cases. - Provide recommendations for bug fixes or enhancements based on test outcomes. @@ -1319,98 +1463,110 @@ This manual test plan will help ensure that the `CodeChatAction` behaves as expe # generic\VoiceToTextAction.kt - #### Manual Test Plan for VoiceToTextAction Class - ##### Objective: -To ensure that the `VoiceToTextAction` class functions correctly, handling audio input, processing it, and converting it into text which is then inserted into the editor at the correct position. +To ensure that the `VoiceToTextAction` class functions correctly, handling audio input, processing it, and converting it into text which is then inserted into +the editor at the correct position. ##### Test Environment: + - IDE with the plugin installed (e.g., IntelliJ IDEA). - Operating system with audio input capabilities. - Microphone setup and configured. - ##### Prerequisites: + - Plugin is installed and enabled in the IDE. - Microphone is connected and set as the default recording device. - ##### Test Cases: - ###### TC1: Basic Dictation Functionality + **Objective**: Verify that the dictation starts, processes audio, and the text is inserted into the editor. + 1. Open a project and a file in the IDE. 2. Place the cursor in the editor where the text should be inserted. 3. Trigger the `VoiceToTextAction`. 4. Speak a few sentences into the microphone. 5. Verify that: - - The recording starts and the status dialog appears. - - The audio is processed, and the speech-to-text conversion happens. - - The text appears in the editor at the cursor's position. + +- The recording starts and the status dialog appears. +- The audio is processed, and the speech-to-text conversion happens. +- The text appears in the editor at the cursor's position. + 6. Close the status dialog to stop the recording. 7. Check the final text in the editor for accuracy. - ###### TC2: Dictation with Selected Text + **Objective**: Ensure that dictation handles initial prompts from selected text correctly. + 1. Open a project and a file in the IDE. 2. Select a portion of text in the editor. 3. Trigger the `VoiceToTextAction`. 4. Speak a continuation of the selected text. 5. Verify that: - - The selected text is used as a prompt. - - The dictated text follows the selected text logically and grammatically. + +- The selected text is used as a prompt. +- The dictated text follows the selected text logically and grammatically. + 6. Close the status dialog to end the session. 7. Review the text for logical continuation and correctness. - ###### TC3: Error Handling + **Objective**: Test the error handling when an exception occurs during recording or processing. + 1. Open a project and a file in the IDE. 2. Trigger the `VoiceToTextAction`. 3. During recording, simulate an error (e.g., disconnect the microphone). 4. Verify that: - - An error message is displayed. - - The process stops gracefully without crashing the IDE. -5. Reconnect the microphone and restart the dictation to check recovery. +- An error message is displayed. +- The process stops gracefully without crashing the IDE. + +5. Reconnect the microphone and restart the dictation to check recovery. ###### TC4: Concurrency and Performance + **Objective**: Ensure that the system remains responsive and performs well under load. + 1. Open multiple files in the IDE. 2. Start dictation in one file. 3. While dictation is ongoing, switch to another file and edit text manually. 4. Verify that: - - The IDE remains responsive. - - There are no lags or freezes in either the dictation or manual editing processes. +- The IDE remains responsive. +- There are no lags or freezes in either the dictation or manual editing processes. ###### TC5: Stop Dictation Midway + **Objective**: Verify that stopping the dictation midway works correctly. + 1. Open a project and a file in the IDE. 2. Trigger the `VoiceToTextAction`. 3. Start dictating and then abruptly close the status dialog to stop dictation. 4. Verify that: - - The dictation stops immediately. - - Partially dictated text remains in the editor and is correct up to the point of stopping. +- The dictation stops immediately. +- Partially dictated text remains in the editor and is correct up to the point of stopping. ##### Test Data: + - Various sentences covering simple to complex structures for dictation. - Texts with technical terms and IDE-specific terminology. - ##### Reporting: + - Document the results for each test case. - Include screenshots or video captures where necessary. - Log any discrepancies or issues in a defect tracking system. - ##### Cleanup: + - Restore any settings changed during testing. - Remove test artifacts from the IDE environment. @@ -1418,266 +1574,291 @@ This manual test plan will help ensure that the `VoiceToTextAction` class functi # generic\CreateFileFromDescriptionAction.kt - #### Manual Test Plan for `CreateFileFromDescriptionAction` Class - ##### Objective: -To verify that the `CreateFileFromDescriptionAction` class functions correctly, creating new files based on directives provided by the user, and handling file paths and naming conflicts appropriately. +To verify that the `CreateFileFromDescriptionAction` class functions correctly, creating new files based on directives provided by the user, and handling file +paths and naming conflicts appropriately. ##### Test Environment Setup: + - Ensure the testing environment has access to a Java development setup with necessary libraries installed. - Clone or have access to the repository containing the `CreateFileFromDescriptionAction` class. - Setup an instance of the `AppSettingsState` with appropriate configurations for the chat model and temperature settings. - ##### Test Data: + - Various directives for file creation, ranging from simple to complex requirements. - Different project structures to test path calculations and file creation in nested directories. - ##### Test Cases: - ###### Test Case 1: Basic File Creation + **Objective**: Verify that a simple file can be created with basic content. **Steps**: + 1. Set up a directive that specifies creating a simple Java class file. 2. Invoke the `processSelection` method with a mock `SelectionState` pointing to a valid project directory. 3. Check if the file is created in the correct location with the specified content. - ###### Test Case 2: File Creation with Path Calculation + **Objective**: Test the path calculation logic when the selected file is in a subdirectory or uses relative paths. **Steps**: + 1. Provide a directive that includes creating a file in a subdirectory. 2. Use a `SelectionState` where `selectedFile` includes relative paths (e.g., `../src/Main.java`). 3. Ensure the file is created in the correct directory relative to the project root. - ###### Test Case 3: Handling Existing Files + **Objective**: Ensure the system correctly handles scenarios where the file already exists. **Steps**: + 1. Create a directive to generate a file that already exists in the target directory. 2. Run the `processSelection` method and check if the file is renamed appropriately to avoid overwriting the existing file. - ###### Test Case 4: Error Handling + **Objective**: Verify that the system handles errors gracefully, such as invalid paths or permissions issues. **Steps**: + 1. Set up a directive that tries to create a file in a non-writable directory. 2. Attempt to create the file and catch any exceptions. 3. Verify that appropriate error messages are logged or returned. - ###### Test Case 5: Complex File Content + **Objective**: Test the system's ability to handle complex file content generation based on the directive. **Steps**: + 1. Provide a complex directive that requires generating a file with multiple classes or special characters. 2. Check if the file is created with the correct content, preserving all special formatting and characters. - ###### Test Case 6: Integration with Chat Model + **Objective**: Ensure that the chat model integration works correctly and the responses are parsed correctly. **Steps**: + 1. Mock the chat model response to return a predetermined output. 2. Verify that the `generateFile` method correctly interprets the chat model's response and creates the file accordingly. - ##### Reporting: + - Document all test results, including success or failure status for each test case. - Include any error messages or stack traces in case of failures. - Provide recommendations for bug fixes or enhancements based on the test outcomes. - ##### Cleanup: + - Remove any files or directories created during testing. - Reset any configurations changed during the test setup. -This manual test plan will help ensure that the `CreateFileFromDescriptionAction` class meets its functional requirements and handles various scenarios gracefully. +This manual test plan will help ensure that the `CreateFileFromDescriptionAction` class meets its functional requirements and handles various scenarios +gracefully. # generic\DiffChatAction.kt - #### Manual Test Plan for DiffChatAction - ##### Objective: -To validate the functionality of the `DiffChatAction` class, ensuring it correctly handles user interactions for generating and applying code diffs through a chat interface. +To validate the functionality of the `DiffChatAction` class, ensuring it correctly handles user interactions for generating and applying code diffs through a +chat interface. ##### Pre-requisites: + 1. IntelliJ IDEA or compatible IDE installed. 2. Plugin containing the `DiffChatAction` class installed and enabled in the IDE. 3. Access to a project with source code files in the IDE. 4. Network access for server communication. - ##### Test Environment: + - Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur] - IDE: IntelliJ IDEA [Specify version] - Plugin Version: [Specify version] - ##### Test Data: -- Source code files in various programming languages supported by the plugin. +- Source code files in various programming languages supported by the plugin. ##### Test Cases: - ###### TC1: Basic Invocation and UI Display + **Objective**: Verify that the DiffChatAction can be triggered and the UI is displayed correctly. + 1. Open a source code file in the IDE. 2. Right-click and select the `Diff Chat` option from the context menu. 3. Observe that a new browser window or tab opens displaying the chat interface. 4. Verify that the chat interface loads without errors and displays the initial system prompt correctly. - ###### TC2: Code Selection Handling + **Objective**: Ensure the action correctly handles both selected and full document text. + 1. Select a portion of text in an open document and invoke the `Diff Chat` action. 2. Verify that only the selected text is sent to the chat interface. 3. Repeat the test without any text selected and verify that the entire document text is sent to the chat interface. - ###### TC3: Diff Formatting and Response Rendering + **Objective**: Test the system's ability to handle diff formatting in user responses and render the proposed changes. + 1. Start a chat session with some code. 2. Input a diff formatted response as per the system's instructions. 3. Verify that the response is rendered correctly in the chat interface, showing visual diff (additions and deletions). 4. Check if the "apply diff" links are functional and correctly modify the code in the IDE when clicked. - ###### TC4: Error Handling + **Objective**: Ensure the system gracefully handles errors. + 1. Input an incorrectly formatted diff response. 2. Verify that the system provides a meaningful error message or guidance. 3. Attempt to invoke the action with no open editor or document, and verify that it fails gracefully, possibly with a user notification. - ###### TC5: Session Management + **Objective**: Confirm that sessions are handled correctly. + 1. Open multiple instances of the chat interface with different code files. 2. Ensure that each session maintains its state independently. 3. Close and reopen the browser or tab, and verify if the session persists or restarts correctly based on the designed behavior. - ###### TC6: Network Failure Simulation + **Objective**: Test the robustness of the application under network failure conditions. + 1. Start a chat session and then simulate a network failure (e.g., by disabling network connectivity). 2. Attempt to submit a diff and observe how the application behaves (e.g., error messages, retry mechanisms). 3. Restore network connectivity and verify if the session resumes or needs to be restarted. - ##### Post-Test Cleanup: + - Close all open sessions and browser instances. - Restore any modified code files to their original state if not done automatically by the test. - ##### Reporting: -Document all findings with screenshots and logs where applicable. Report any deviations from expected outcomes, including any UI issues, functionality bugs, or crashes. -# generic\LineFilterChatAction.kt +Document all findings with screenshots and logs where applicable. Report any deviations from expected outcomes, including any UI issues, functionality bugs, or +crashes. +# generic\LineFilterChatAction.kt #### Manual Test Plan for LineFilterChatAction - ##### Objective: -To validate the functionality of the `LineFilterChatAction` class, ensuring that it correctly handles user interactions, processes code, and integrates with the chat system for code assistance. +To validate the functionality of the `LineFilterChatAction` class, ensuring that it correctly handles user interactions, processes code, and integrates with the +chat system for code assistance. ##### Prerequisites: + - IntelliJ IDEA or compatible IDE installed. - Plugin containing the `LineFilterChatAction` installed and enabled in the IDE. - Access to a project with source code files in the IDE. - Network access for the chat server functionality. - ##### Test Environment: + - Operating System: [Specify OS] - IDE Version: [Specify IDE version] - Plugin Version: [Specify Plugin version] - Dependencies: Ensure all dependencies are correctly configured, including necessary servers and services running. - ##### Test Cases: - ###### TC1: Basic Invocation + **Objective**: Verify that the action can be triggered from the IDE. + 1. Open a source code file in the IDE. 2. Select a portion of code or simply place the cursor within the document. 3. Trigger the `LineFilterChatAction` via its assigned shortcut or menu entry. -4. **Expected Result**: - - The action initializes without errors. - - A browser window/tab opens pointing to the chat interface. +4. **Expected Result**: +- The action initializes without errors. +- A browser window/tab opens pointing to the chat interface. ###### TC2: No Selection Handling + **Objective**: Verify the action's behavior when no text is selected. + 1. Open a source code file and ensure no text is selected. 2. Trigger the `LineFilterChatAction`. -3. **Expected Result**: - - The entire text of the current document is used as input for the chat session. +3. **Expected Result**: +- The entire text of the current document is used as input for the chat session. ###### TC3: Error Handling - Unsupported File Type + **Objective**: Verify that the action handles unsupported file types gracefully. + 1. Open a file of an unsupported type (e.g., a binary file). 2. Attempt to trigger the `LineFilterChatAction`. -3. **Expected Result**: - - The action does not proceed. - - An appropriate error message or notification is displayed. +3. **Expected Result**: +- The action does not proceed. +- An appropriate error message or notification is displayed. ###### TC4: Chat Interaction + **Objective**: Test the chat functionality with the AI. + 1. Trigger the action with a selected portion of code. 2. In the opened chat interface, ask specific questions related to the code. -3. **Expected Result**: - - The AI responds accurately based on the provided code context. - - Responses include appropriate references to the code lines. +3. **Expected Result**: +- The AI responds accurately based on the provided code context. +- Responses include appropriate references to the code lines. ###### TC5: Session Management + **Objective**: Ensure that sessions are handled and stored correctly. + 1. Open multiple code files and trigger the action in each. 2. Interact with the chat in each session. 3. Navigate between different chat sessions. -4. **Expected Result**: - - Each session maintains its state independently. - - Switching between sessions displays the correct chat history and code context. +4. **Expected Result**: +- Each session maintains its state independently. +- Switching between sessions displays the correct chat history and code context. ###### TC6: Network Failure Handling + **Objective**: Verify the system's resilience to network issues. + 1. Trigger the action with a network connection active. 2. During the chat session, simulate a network failure (e.g., disable network connectivity). 3. Attempt to continue the interaction. 4. Restore network connectivity and try interacting again. -5. **Expected Result**: - - During network failure, the system should handle the loss gracefully, possibly with error notifications. - - After connectivity is restored, the system should resume normal operation. +5. **Expected Result**: +- During network failure, the system should handle the loss gracefully, possibly with error notifications. +- After connectivity is restored, the system should resume normal operation. ###### TC7: Code Update Reflection + **Objective**: Verify that updates to code are reflected in the chat when the action is re-triggered. + 1. Open a source code file, trigger the action, and start a chat session. 2. Close the chat, modify the code in the IDE, and trigger the action again. -3. **Expected Result**: - - The new chat session should reflect the updated code. +3. **Expected Result**: +- The new chat session should reflect the updated code. ##### Reporting: + - Document all test results, noting any failures or unexpected behaviors. - Capture screenshots or logs where applicable. - Provide feedback and suggestions for improvement based on test outcomes. - ##### Cleanup: + - Close all open sessions and browser tabs related to testing. - Restore any settings changed during testing to their original state. @@ -1685,411 +1866,463 @@ This manual test plan will help ensure that the `LineFilterChatAction` behaves a # generic\MultiStepPatchAction.kt - #### Manual Test Plan for MultiStepPatchAction - ##### Objective: -To verify the functionality and robustness of the `MultiStepPatchAction` class, ensuring it correctly handles user interactions, processes data, and integrates with the system environment and other components. +To verify the functionality and robustness of the `MultiStepPatchAction` class, ensuring it correctly handles user interactions, processes data, and integrates +with the system environment and other components. ##### Test Environment: + - IDE (e.g., IntelliJ IDEA) with the plugin installed. - Access to a local or remote development server. - Necessary permissions to read from and write to the project directories. - Java Development Kit (JDK) installed. - ##### Pre-conditions: + - The plugin containing `MultiStepPatchAction` is properly installed and enabled in the IDE. - The user has a project open in the IDE with multiple files for testing. - ##### Test Cases: 1. **Initialization Test** - - **Objective**: Ensure the `MultiStepPatchAction` initializes correctly within the IDE environment. - - **Steps**: - 1. Start the IDE. - 2. Open a project. - 3. Trigger the `MultiStepPatchAction`. - - **Expected Result**: The action initializes without errors, and the Auto Dev Assistant UI is accessible. + +- **Objective**: Ensure the `MultiStepPatchAction` initializes correctly within the IDE environment. +- **Steps**: + 1. Start the IDE. + 2. Open a project. + 3. Trigger the `MultiStepPatchAction`. +- **Expected Result**: The action initializes without errors, and the Auto Dev Assistant UI is accessible. 2. **UI Accessibility Test** - - **Objective**: Verify that the Auto Dev Assistant UI opens in the default browser and displays correctly. - - **Steps**: - 1. Trigger the `MultiStepPatchAction`. - 2. Observe the browser opening automatically. - - **Expected Result**: The Auto Dev Assistant UI is displayed correctly in the browser with all elements visible. + +- **Objective**: Verify that the Auto Dev Assistant UI opens in the default browser and displays correctly. +- **Steps**: + 1. Trigger the `MultiStepPatchAction`. + 2. Observe the browser opening automatically. +- **Expected Result**: The Auto Dev Assistant UI is displayed correctly in the browser with all elements visible. 3. **Session Handling Test** - - **Objective**: Confirm that sessions are handled correctly, allowing multiple instances without conflict. - - **Steps**: - 1. Trigger the `MultiStepPatchAction` multiple times with different projects. - 2. Navigate between different sessions in the browser. - - **Expected Result**: Each session should maintain its state independently. + +- **Objective**: Confirm that sessions are handled correctly, allowing multiple instances without conflict. +- **Steps**: + 1. Trigger the `MultiStepPatchAction` multiple times with different projects. + 2. Navigate between different sessions in the browser. +- **Expected Result**: Each session should maintain its state independently. 4. **File Selection and Data Storage Interaction** - - **Objective**: Ensure that the action correctly handles file selections and interacts with the data storage. - - **Steps**: - 1. Select different folders and files in the IDE. - 2. Trigger the `MultiStepPatchAction`. - 3. Check if the selected files are correctly recognized and listed in the UI. - - **Expected Result**: The selected files should be correctly passed to the Auto Dev Assistant and displayed in the UI. + +- **Objective**: Ensure that the action correctly handles file selections and interacts with the data storage. +- **Steps**: + 1. Select different folders and files in the IDE. + 2. Trigger the `MultiStepPatchAction`. + 3. Check if the selected files are correctly recognized and listed in the UI. +- **Expected Result**: The selected files should be correctly passed to the Auto Dev Assistant and displayed in the UI. 5. **Task Generation and Display** - - **Objective**: Test the generation and display of tasks based on user input. - - **Steps**: - 1. Provide a specific development directive in the UI. - 2. Observe the tasks generated by the system. - - **Expected Result**: Tasks relevant to the user's directive are generated and displayed correctly. + +- **Objective**: Test the generation and display of tasks based on user input. +- **Steps**: + 1. Provide a specific development directive in the UI. + 2. Observe the tasks generated by the system. +- **Expected Result**: Tasks relevant to the user's directive are generated and displayed correctly. 6. **Error Handling Test** - - **Objective**: Ensure that the system gracefully handles errors. - - **Steps**: - 1. Trigger scenarios likely to produce errors (e.g., invalid file paths, unsupported operations). - 2. Observe the system's response. - - **Expected Result**: Errors are handled gracefully, with informative messages displayed to the user without crashing the system. + +- **Objective**: Ensure that the system gracefully handles errors. +- **Steps**: + 1. Trigger scenarios likely to produce errors (e.g., invalid file paths, unsupported operations). + 2. Observe the system's response. +- **Expected Result**: Errors are handled gracefully, with informative messages displayed to the user without crashing the system. 7. **Concurrency Test** - - **Objective**: Verify that the system handles concurrent operations without data corruption or crashes. - - **Steps**: - 1. Trigger multiple instances of `MultiStepPatchAction` simultaneously. - 2. Perform operations in multiple UI sessions at the same time. - - **Expected Result**: All operations are processed correctly without interference, data corruption, or system crashes. + +- **Objective**: Verify that the system handles concurrent operations without data corruption or crashes. +- **Steps**: + 1. Trigger multiple instances of `MultiStepPatchAction` simultaneously. + 2. Perform operations in multiple UI sessions at the same time. +- **Expected Result**: All operations are processed correctly without interference, data corruption, or system crashes. 8. **Cleanup and Session Termination** - - **Objective**: Confirm that sessions are cleaned up properly after termination. - - **Steps**: - 1. Close the browser or terminate sessions from the UI. - 2. Check system resources and logs for any remnants. - - **Expected Result**: All resources are released, and no session data remains after termination. +- **Objective**: Confirm that sessions are cleaned up properly after termination. +- **Steps**: + 1. Close the browser or terminate sessions from the UI. + 2. Check system resources and logs for any remnants. +- **Expected Result**: All resources are released, and no session data remains after termination. ##### Post-conditions: + - All test data created during the testing should be cleaned up. - The system should be restored to its initial state before testing. - ##### Reporting: + - All findings from the test cases should be documented, including any discrepancies from the expected results. - Severity and priority should be assigned to each finding for further action and resolution. -This manual test plan provides a structured approach to validate the functionality and reliability of the `MultiStepPatchAction` within a development environment. Adjustments may be necessary based on specific configurations or additional requirements. +This manual test plan provides a structured approach to validate the functionality and reliability of the `MultiStepPatchAction` within a development +environment. Adjustments may be necessary based on specific configurations or additional requirements. # generic\RedoLast.kt - #### Manual Test Plan for RedoLast Action in IntelliJ - ##### Objective: -To verify that the RedoLast action correctly redoes the last AI Coder action performed in the IntelliJ editor. +To verify that the RedoLast action correctly redoes the last AI Coder action performed in the IntelliJ editor. ##### Prerequisites: + - IntelliJ IDEA must be installed and running. - The AI Coder plugin, including the RedoLast action, must be installed and enabled in IntelliJ. - A project with at least one file must be open in the editor. - ##### Test Environment: + - Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur] - IntelliJ IDEA version: [Specify version - e.g., 2021.3] - AI Coder plugin version: [Specify version] - ##### Test Data: -- Various code files in different languages supported by the plugin (e.g., Java, Kotlin, Python). +- Various code files in different languages supported by the plugin (e.g., Java, Kotlin, Python). ##### Test Cases: - ###### TC1: Basic Redo Functionality + 1. **Objective**: Ensure that the RedoLast action can redo a simple undone action. 2. **Steps**: - - Open a file in the editor. - - Perform a simple action (e.g., typing a line of code). - - Undo the action using IntelliJ's built-in undo feature. - - Trigger the RedoLast action. -3. **Expected Result**: The undone action should be redone correctly. +- Open a file in the editor. +- Perform a simple action (e.g., typing a line of code). +- Undo the action using IntelliJ's built-in undo feature. +- Trigger the RedoLast action. + +3. **Expected Result**: The undone action should be redone correctly. ###### TC2: Redo After Multiple Actions + 1. **Objective**: Verify that RedoLast redoes the last undone action after multiple changes. 2. **Steps**: - - Open a file and perform multiple editing actions (e.g., add several lines of code). - - Undo several actions one by one. - - Trigger the RedoLast action. -3. **Expected Result**: Only the last undone action should be redone. +- Open a file and perform multiple editing actions (e.g., add several lines of code). +- Undo several actions one by one. +- Trigger the RedoLast action. + +3. **Expected Result**: Only the last undone action should be redone. ###### TC3: Redo With No Prior Action + 1. **Objective**: Check the behavior when there is no action to redo. 2. **Steps**: - - Open a new or existing file. - - Ensure no actions are performed or undo any performed actions. - - Trigger the RedoLast action. -3. **Expected Result**: No changes should occur in the editor. The action should handle the absence of redoable actions gracefully. +- Open a new or existing file. +- Ensure no actions are performed or undo any performed actions. +- Trigger the RedoLast action. + +3. **Expected Result**: No changes should occur in the editor. The action should handle the absence of redoable actions gracefully. ###### TC4: Redo in Different File Types + 1. **Objective**: Ensure that RedoLast works across files of different types. 2. **Steps**: - - Repeat TC1 for different file types (e.g., .java, .kt, .py). -3. **Expected Result**: The RedoLast action should function correctly regardless of the file type. +- Repeat TC1 for different file types (e.g., .java, .kt, .py). + +3. **Expected Result**: The RedoLast action should function correctly regardless of the file type. ###### TC5: Redo After Restarting IntelliJ + 1. **Objective**: Verify that RedoLast can still function after restarting IntelliJ. 2. **Steps**: - - Open a file, perform some actions, and undo at least one. - - Close and reopen IntelliJ. - - Open the same file and trigger the RedoLast action. -3. **Expected Result**: The last undone action should be redone correctly, assuming session persistence for undo/redo stacks. +- Open a file, perform some actions, and undo at least one. +- Close and reopen IntelliJ. +- Open the same file and trigger the RedoLast action. + +3. **Expected Result**: The last undone action should be redone correctly, assuming session persistence for undo/redo stacks. ##### Reporting: + - Document the outcome of each test case. - Capture any discrepancies from the expected results as defects. - Include screenshots or video captures if applicable. - ##### Cleanup: + - Revert any changes made to the code files during testing to maintain a clean state. This test plan ensures comprehensive coverage of the RedoLast functionality within the AI Coder plugin, addressing different scenarios and edge cases. # generic\MultiDiffChatAction.kt - #### Manual Test Plan for MultiDiffChatAction - ##### Objective: -To ensure that the `MultiDiffChatAction` class functions correctly across various scenarios, handling file differences and chat interactions as expected within an IDE environment. +To ensure that the `MultiDiffChatAction` class functions correctly across various scenarios, handling file differences and chat interactions as expected within +an IDE environment. ##### Test Environment: + - IDE with plugin support (e.g., IntelliJ IDEA) - Access to the plugin that includes the `MultiDiffChatAction` - Necessary permissions to read/write files and access the internet - Desktop environment capable of opening a web browser - ##### Pre-conditions: + - The plugin containing `MultiDiffChatAction` is installed and enabled in the IDE. - Test files with various programming languages are available within the project or workspace. - ##### Test Cases: - ###### TC1: Basic Functionality Check + **Objective**: Verify that the action can be triggered and the chat interface opens in the default browser. + 1. Right-click on a file or a selection of files in the project explorer. 2. Select the `MultiDiffChat` action. -3. **Expected Result**: - - A new browser tab opens pointing to the chat interface. - - The chat interface displays the initial code summary correctly. +3. **Expected Result**: +- A new browser tab opens pointing to the chat interface. +- The chat interface displays the initial code summary correctly. ###### TC2: Multi-file Handling + **Objective**: Ensure that the action correctly handles multiple files. + 1. Select multiple files with different extensions from the project explorer. 2. Trigger the `MultiDiffChat` action. 3. **Expected Result**: - - The chat interface shows a code summary for each selected file. - - Language detection works as expected for different file types. +- The chat interface shows a code summary for each selected file. +- Language detection works as expected for different file types. ###### TC3: No File Selected + **Objective**: Check the behavior when no file is selected. + 1. Ensure no file is selected in the project explorer. 2. Trigger the `MultiDiffChat` action. 3. **Expected Result**: - - An error message appears indicating that no file was selected or an automatic fallback to a default directory occurs. +- An error message appears indicating that no file was selected or an automatic fallback to a default directory occurs. ###### TC4: File Updates + **Objective**: Test if the code updates are correctly applied to the files. + 1. Select a file and trigger the `MultiDiffChat` action. 2. In the chat interface, submit a code change suggestion. 3. Accept the change in the IDE. 4. **Expected Result**: - - The file in the IDE is updated with the new code. - - The document is saved automatically if changes are applied. +- The file in the IDE is updated with the new code. +- The document is saved automatically if changes are applied. ###### TC5: Error Handling + **Objective**: Ensure that errors are handled gracefully. + 1. Manipulate the environment to simulate an error (e.g., permissions issues, network failures). 2. Trigger the `MultiDiffChat` action. 3. **Expected Result**: - - Appropriate error messages are displayed. - - The system logs the error details for debugging. +- Appropriate error messages are displayed. +- The system logs the error details for debugging. ###### TC6: Session Management + **Objective**: Verify that sessions are managed correctly. + 1. Open the chat interface using the `MultiDiffChat` action. 2. Close the browser or navigate away from the chat page. 3. Reopen the chat interface. 4. **Expected Result**: - - The previous session should either continue where it left off or a new session should start cleanly. +- The previous session should either continue where it left off or a new session should start cleanly. ###### TC7: Browser Compatibility + **Objective**: Ensure the chat interface works across different browsers. + 1. Trigger the `MultiDiffChat` action using different browsers (e.g., Chrome, Firefox, Edge). 2. **Expected Result**: - - The chat interface functions correctly in all tested browsers. +- The chat interface functions correctly in all tested browsers. ##### Post-conditions: + - Verify that all files are intact and contain expected changes if any were made. - Ensure no residual data or sessions are left that could affect subsequent tests. - ##### Cleanup: + - Revert any changes made to files during testing. - Clear any test data or configurations that were set up for testing purposes. - #### Notes: + - Each test should be documented with screenshots or video captures where applicable. - Any anomalies or deviations from the expected results should be logged and investigated. # generic\GenerateDocumentationAction.kt - #### Manual Test Plan for GenerateDocumentationAction - ##### Objective -To verify that the `GenerateDocumentationAction` class functions correctly, allowing users to compile documentation from selected files using AI-generated content. +To verify that the `GenerateDocumentationAction` class functions correctly, allowing users to compile documentation from selected files using AI-generated +content. ##### Test Environment + - IDE: IntelliJ IDEA (or compatible IDE) - Plugin: Ensure the plugin containing `GenerateDocumentationAction` is installed and enabled. - Operating System: Windows, macOS, or Linux - ##### Pre-requisites + - The plugin containing the `GenerateDocumentationAction` is installed and enabled in the IDE. - Sample project files are available within the IDE for testing. - ##### Test Cases - ###### TC1: Basic Functionality Test + **Objective**: To verify that the action compiles documentation from selected files. + 1. **Steps**: - - Right-click on a folder containing multiple source files. - - Select the "Compile Documentation" option. - - In the dialog, select multiple files to process. - - Enter a specific AI instruction in the provided text area. - - Specify an output filename. - - Click OK to generate the documentation. + +- Right-click on a folder containing multiple source files. +- Select the "Compile Documentation" option. +- In the dialog, select multiple files to process. +- Enter a specific AI instruction in the provided text area. +- Specify an output filename. +- Click OK to generate the documentation. + 2. **Expected Result**: - - A markdown file with the specified name is created in the same directory. - - The file contains compiled documentation based on the AI transformation of the selected files. +- A markdown file with the specified name is created in the same directory. +- The file contains compiled documentation based on the AI transformation of the selected files. ###### TC2: Validation of Output File Naming + **Objective**: To verify that the system handles existing filenames correctly by creating a new file with an incremented index. + 1. **Steps**: - - Repeat TC1 but specify an output filename that already exists. + +- Repeat TC1 but specify an output filename that already exists. + 2. **Expected Result**: - - A new file is created with an incremented index in its name (e.g., `compiled_documentation.1.md`). +- A new file is created with an incremented index in its name (e.g., `compiled_documentation.1.md`). ###### TC3: AI Instruction Impact + **Objective**: To verify that changing the AI instruction affects the generated documentation content. + 1. **Steps**: - - Perform TC1 with a basic instruction. - - Repeat the process with a more detailed or different instruction. + +- Perform TC1 with a basic instruction. +- Repeat the process with a more detailed or different instruction. + 2. **Expected Result**: - - The content of the generated documentation should reflect the differences dictated by the AI instructions. +- The content of the generated documentation should reflect the differences dictated by the AI instructions. ###### TC4: No Files Selected + **Objective**: To verify the system behavior when no files are selected for processing. + 1. **Steps**: - - Open the "Compile Documentation" dialog. - - Deselect all files. - - Provide an AI instruction and output filename. - - Click OK. + +- Open the "Compile Documentation" dialog. +- Deselect all files. +- Provide an AI instruction and output filename. +- Click OK. + 2. **Expected Result**: - - No output file is created. - - A user-friendly message or indication that no files were processed. +- No output file is created. +- A user-friendly message or indication that no files were processed. ###### TC5: Error Handling + **Objective**: To verify that the system handles errors gracefully (e.g., permission issues, corrupted files). + 1. **Steps**: - - Introduce a controlled error scenario such as permissions restrictions on a file. - - Attempt to compile documentation including the problematic file. + +- Introduce a controlled error scenario such as permissions restrictions on a file. +- Attempt to compile documentation including the problematic file. + 2. **Expected Result**: - - The process should not crash. - - An error message should be displayed, indicating the nature of the problem. +- The process should not crash. +- An error message should be displayed, indicating the nature of the problem. ###### TC6: UI Elements and Responsiveness + **Objective**: To verify that all UI elements are responsive and function as expected. + 1. **Steps**: - - Open the "Compile Documentation" dialog. - - Interact with all UI elements (checkboxes, text fields, buttons). + +- Open the "Compile Documentation" dialog. +- Interact with all UI elements (checkboxes, text fields, buttons). + 2. **Expected Result**: - - All elements should be responsive. - - Changes in the UI should reflect immediately (e.g., text updates, checkbox selections). +- All elements should be responsive. +- Changes in the UI should reflect immediately (e.g., text updates, checkbox selections). ##### Post-Test Cleanup + - Remove any test files or directories created during testing. - Restore any settings changed during testing to their original state. - ##### Reporting + - Document any discrepancies from the expected results. - Capture screenshots or logs if applicable. - Provide a detailed report to the development team for any failures or bugs encountered. # generic\ReplaceWithSuggestionsAction.kt - #### Manual Test Plan for `ReplaceWithSuggestionsAction` Class - ##### Objective -To verify that the `ReplaceWithSuggestionsAction` class functions correctly, providing appropriate suggestions for text replacement based on the selected text within an IDE environment. +To verify that the `ReplaceWithSuggestionsAction` class functions correctly, providing appropriate suggestions for text replacement based on the selected text +within an IDE environment. ##### Pre-requisites + - IntelliJ IDEA or a compatible IDE installed. - Plugin containing the `ReplaceWithSuggestionsAction` class is installed and enabled in the IDE. - A project is open in the IDE with at least one editable file. - ##### Test Environment + - Operating System: [Specify OS] - IDE Version: [Specify IDE version] - Plugin Version: [Specify Plugin version] - ##### Test Data -- Various code snippets and text blocks of varying lengths and contexts. +- Various code snippets and text blocks of varying lengths and contexts. ##### Test Cases - ###### TC1: Basic Functionality Test + **Objective**: Ensure that the action triggers and provides suggestions. **Steps**: + 1. Open a file in the IDE. 2. Select a portion of text. 3. Trigger the `ReplaceWithSuggestionsAction`. @@ -2097,476 +2330,534 @@ To verify that the `ReplaceWithSuggestionsAction` class functions correctly, pro **Expected Result**: A dialog with suggested replacements should appear. - ###### TC2: No Selection Test + **Objective**: Verify behavior when no text is selected. **Steps**: + 1. Ensure no text is selected. 2. Trigger the `ReplaceWithSuggestionsAction`. 3. Observe the behavior. **Expected Result**: No action should be taken, or a user-friendly message should be displayed indicating no text is selected. - ###### TC3: Large Text Selection + **Objective**: Test the action with a large text selection. **Steps**: + 1. Select a large block of text (e.g., several paragraphs or a complete function). 2. Trigger the `ReplaceWithSuggestionsAction`. 3. Observe the suggestions provided. **Expected Result**: The action should handle large texts gracefully, possibly truncating or summarizing the context appropriately. - ###### TC4: Edge Case with Special Characters + **Objective**: Ensure special characters in the text do not cause errors. **Steps**: + 1. Select text that includes special characters (e.g., symbols, non-ASCII characters). 2. Trigger the `ReplaceWithSuggestionsAction`. 3. Check if the suggestions are generated without errors. **Expected Result**: Suggestions are generated without errors, and special characters are handled correctly. - ###### TC5: Response to API Failure + **Objective**: Determine the behavior when the backend API fails or is unavailable. **Steps**: + 1. Simulate API failure (e.g., by disconnecting from the network or using a mock to force a failure). 2. Trigger the `ReplaceWithSuggestionsAction`. 3. Observe the behavior. **Expected Result**: The action should handle API failures gracefully, notifying the user of the issue without crashing. - ###### TC6: Performance Test + **Objective**: Ensure the action performs well under typical conditions. **Steps**: + 1. Select a reasonable amount of text. 2. Trigger the `ReplaceWithSuggestionsAction` multiple times in quick succession. 3. Observe any lag or performance degradation. **Expected Result**: The action should perform efficiently without significant delays or resource consumption spikes. - ##### Reporting + - Document all test results, including any deviations from expected outcomes. - Capture screenshots or video recordings for UI-related tests. - Log any errors or exceptions encountered during testing. - ##### Post-Test Cleanup + - Restore any settings or configurations changed during testing to their original state. - Close and reopen the IDE to clear any temporary states or caches if necessary. -This manual test plan will help ensure that the `ReplaceWithSuggestionsAction` behaves as expected across various scenarios and handles edge cases and errors gracefully. +This manual test plan will help ensure that the `ReplaceWithSuggestionsAction` behaves as expected across various scenarios and handles edge cases and errors +gracefully. # generic\PlanAheadAction.kt - #### Manual Test Plan for PlanAheadAction and TaskRunnerApp - ##### Objective: -To verify the functionality and robustness of the PlanAheadAction and TaskRunnerApp components, ensuring they handle task creation, session management, and user interactions correctly. +To verify the functionality and robustness of the PlanAheadAction and TaskRunnerApp components, ensuring they handle task creation, session management, and user +interactions correctly. ##### Test Environment: + - IDE with the plugin installed (e.g., IntelliJ IDEA) - Access to a local or remote server environment where the AppServer is running - Necessary permissions to read and write files and execute commands on the system - ##### Test Data: + - Various project files including different file types and sizes - User input scenarios including valid and invalid commands - Configuration settings for different user roles and permissions - ##### Test Cases: - ###### TC1: Initialization and Session Creation + **Objective**: Verify that a new session is created successfully when the action is triggered. + 1. Trigger the PlanAheadAction from the IDE. 2. Check if a new session ID is generated and stored correctly. 3. Verify that the session is associated with the correct project and user. - ###### TC2: Folder and File Selection + **Objective**: Ensure the application correctly handles the selection of folders and files. + 1. Select a folder and trigger the PlanAheadAction. 2. Verify that the application uses the selected folder as the root. 3. Select a file and trigger the PlanAheadAction. 4. Verify that the application identifies the correct module root based on the file location. - ###### TC3: Task Creation and Execution + **Objective**: Test the creation and execution of tasks based on user input. + 1. Input a valid task description and trigger task creation. 2. Check if the task is created with the correct parameters and dependencies. 3. Execute the task and verify that the expected output or changes are made. 4. Input invalid or incomplete task descriptions and verify that errors are handled gracefully. - ###### TC4: User Interface and Interaction + **Objective**: Ensure that the user interface displays the correct information and responds to user interactions. + 1. Check if the UI correctly displays the session and task details. 2. Use the UI to modify task settings and trigger updates. 3. Verify that changes are reflected in the task execution. 4. Test the responsiveness of the UI under different network conditions. - ###### TC5: Error Handling and Logging + **Objective**: Verify that the application handles errors properly and logs them as expected. + 1. Simulate various error conditions (e.g., file not found, access denied, server error). 2. Verify that the application displays appropriate error messages to the user. 3. Check the logs to ensure that errors are recorded correctly. - ###### TC6: Security and Permissions + **Objective**: Test the application’s handling of security and permissions. + 1. Attempt to execute tasks that require elevated permissions without the necessary rights. 2. Verify that the application prevents unauthorized actions and logs the attempts. 3. Test the application with users having different roles and verify that permissions are enforced according to the role. - ###### TC7: Performance and Scalability + **Objective**: Assess the performance and scalability of the application under load. + 1. Trigger multiple sessions and tasks simultaneously. 2. Monitor the performance metrics such as response time, CPU, and memory usage. 3. Verify that the application scales well and maintains performance as the number of tasks increases. - ##### Test Reporting: + - Document the results of each test case, including the steps taken, expected outcomes, actual outcomes, and any discrepancies. - Include screenshots or logs where applicable to provide evidence of the test results. - Summarize the findings and provide recommendations for improvements or bug fixes. - ##### Conclusion: -This manual test plan aims to cover critical functionalities of the PlanAheadAction and TaskRunnerApp to ensure they meet the required standards for performance, usability, and reliability. Regular testing and updates based on the findings will help maintain the quality of the application. -# generic\WebDevelopmentAssistantAction.kt +This manual test plan aims to cover critical functionalities of the PlanAheadAction and TaskRunnerApp to ensure they meet the required standards for +performance, usability, and reliability. Regular testing and updates based on the findings will help maintain the quality of the application. +# generic\WebDevelopmentAssistantAction.kt #### Manual Test Plan for WebDevelopmentAssistantAction - ##### Objective: -To ensure that the `WebDevelopmentAssistantAction` class and its associated components function correctly across various scenarios, handling user interactions, file operations, and server communications effectively. +To ensure that the `WebDevelopmentAssistantAction` class and its associated components function correctly across various scenarios, handling user interactions, +file operations, and server communications effectively. ##### Test Environment Setup: + 1. **IDE Setup**: Ensure IntelliJ IDEA is installed and configured. 2. **Plugin Installation**: Install the plugin containing the `WebDevelopmentAssistantAction` class. 3. **Server Setup**: Verify that the `AppServer` is up and running. 4. **File System**: Prepare a directory structure with various file types to simulate user projects. 5. **Browser Setup**: Ensure a default browser is set and functional. - ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: Verify that the action initializes and opens a browser window to the correct URL. + 1. **Steps**: - - Right-click on a folder in the project explorer. - - Select the `Web Dev Assistant v1.1` action. + +- Right-click on a folder in the project explorer. +- Select the `Web Dev Assistant v1.1` action. + 2. **Expected Results**: - - A new browser window/tab opens. - - The URL corresponds to the `AppServer` URL with the appropriate session ID appended. +- A new browser window/tab opens. +- The URL corresponds to the `AppServer` URL with the appropriate session ID appended. ###### TC2: Directory Selection Validation + **Objective**: Ensure the action is disabled when a non-directory file is selected. + 1. **Steps**: - - Right-click on a non-directory file in the project explorer. - - Observe the availability of the `Web Dev Assistant v1.1` action. + +- Right-click on a non-directory file in the project explorer. +- Observe the availability of the `Web Dev Assistant v1.1` action. + 2. **Expected Results**: - - The action should be disabled or not visible. +- The action should be disabled or not visible. ###### TC3: Session Handling + **Objective**: Test if new sessions are correctly created and managed. + 1. **Steps**: - - Trigger the action multiple times with different selected directories. - - Observe the creation of new sessions. + +- Trigger the action multiple times with different selected directories. +- Observe the creation of new sessions. + 2. **Expected Results**: - - Each action trigger should result in a new session. - - Each session should have a unique session ID. +- Each action trigger should result in a new session. +- Each session should have a unique session ID. ###### TC4: Error Handling + **Objective**: Verify that the system handles errors gracefully (e.g., failure to open a browser). + 1. **Steps**: - - Temporarily modify system settings to disable the default browser. - - Trigger the action. + +- Temporarily modify system settings to disable the default browser. +- Trigger the action. + 2. **Expected Results**: - - An appropriate error message should be logged. - - The system should not crash. +- An appropriate error message should be logged. +- The system should not crash. ###### TC5: User Message Handling + **Objective**: Ensure that user messages are correctly processed and responded to within the application. + 1. **Steps**: - - Use the browser interface to send a message through the web application. - - Observe the response and any changes in the UI. + +- Use the browser interface to send a message through the web application. +- Observe the response and any changes in the UI. + 2. **Expected Results**: - - The message should be processed. - - A valid response should be displayed in the UI. +- The message should be processed. +- A valid response should be displayed in the UI. ###### TC6: File Generation and Linking + **Objective**: Test the generation of HTML, CSS, and JavaScript files based on user input. + 1. **Steps**: - - Provide specific instructions via the web interface for generating web resources. - - Check the generated files and their content. + +- Provide specific instructions via the web interface for generating web resources. +- Check the generated files and their content. + 2. **Expected Results**: - - Files should be correctly generated in the specified paths. - - Files should contain content that matches the instructions provided. +- Files should be correctly generated in the specified paths. +- Files should contain content that matches the instructions provided. ###### TC7: Code Review and Feedback Integration + **Objective**: Verify that code reviews and feedback are correctly applied to the generated code. + 1. **Steps**: - - Generate some initial code files. - - Use the provided interface to request a code review. - - Apply suggested changes via the interface. + +- Generate some initial code files. +- Use the provided interface to request a code review. +- Apply suggested changes via the interface. + 2. **Expected Results**: - - The system should provide valid code modifications. - - Users should be able to apply these modifications directly from the interface. +- The system should provide valid code modifications. +- Users should be able to apply these modifications directly from the interface. ###### TC8: Multi-Session Interaction + **Objective**: Ensure that multiple sessions can run concurrently without interference. + 1. **Steps**: - - Open multiple sessions from different projects. - - Interact with each session independently. + +- Open multiple sessions from different projects. +- Interact with each session independently. + 2. **Expected Results**: - - Actions in one session should not affect any other sessions. +- Actions in one session should not affect any other sessions. ##### Test Data: + - Sample directories with different structures and content. - Sample user messages for generating web resources. - Code snippets for review. - ##### Reporting: + - Document all test results with screenshots and logs. - Report any discrepancies from expected results for further investigation. - ##### Cleanup: + - Remove any test-specific configurations and files. - Restart the server to clear all sessions and data. -This manual test plan will help ensure that the `WebDevelopmentAssistantAction` behaves as expected under various conditions and handles user interactions correctly. +This manual test plan will help ensure that the `WebDevelopmentAssistantAction` behaves as expected under various conditions and handles user interactions +correctly. # markdown\MarkdownImplementActionGroup.kt - #### Manual Test Plan for MarkdownImplementActionGroup - ##### Objective -To verify that the `MarkdownImplementActionGroup` and its child actions (`MarkdownImplementAction`) function correctly within an IDE environment, enabling users to convert selected text into various programming languages within a Markdown context. +To verify that the `MarkdownImplementActionGroup` and its child actions (`MarkdownImplementAction`) function correctly within an IDE environment, enabling users +to convert selected text into various programming languages within a Markdown context. ##### Test Environment + - IDE (e.g., IntelliJ IDEA) - Java Development Kit (JDK) - Plugin installed and enabled in the IDE - ##### Pre-conditions + - The plugin containing the `MarkdownImplementActionGroup` must be installed and enabled in the IDE. - A project must be open in the IDE with at least one Markdown file. - ##### Test Cases - ###### TC1: Action Visibility and Enablement + **Objective**: Ensure that the action group is only visible and enabled when a Markdown file is active and text is selected. + 1. Open a non-Markdown file and verify that the action group is neither visible nor enabled. 2. Open a Markdown file but do not select any text. Verify that the action group is visible but not enabled. 3. Select text in the Markdown file and verify that the action group is both visible and enabled. - ###### TC2: Action Listing + **Objective**: Verify that all supported languages are listed under the action group when invoked. + 1. Open a Markdown file and select some text. 2. Activate the action group and verify that all expected programming languages are listed (e.g., SQL, Java, Python, etc.). - ###### TC3: Code Conversion Functionality + **Objective**: Test the conversion functionality for each supported language. + 1. For each language in the `markdownLanguages` list: - - Select a block of text in a Markdown file. - - Trigger the `MarkdownImplementAction` for the language. - - Verify that the selected text is converted appropriately into the target language and wrapped in the correct Markdown code block syntax. - - Check for proper escaping and indentation of the generated code. +- Select a block of text in a Markdown file. +- Trigger the `MarkdownImplementAction` for the language. +- Verify that the selected text is converted appropriately into the target language and wrapped in the correct Markdown code block syntax. +- Check for proper escaping and indentation of the generated code. ###### TC4: Error Handling + **Objective**: Ensure that the system handles errors gracefully when the conversion API fails or returns an error. + 1. Simulate API failure scenarios (e.g., network issues, API errors). 2. Attempt to convert selected text using any language action. 3. Verify that the system provides a user-friendly error message and does not crash or hang. - ###### TC5: Performance + **Objective**: Ensure that the action completes within a reasonable time frame. + 1. Select a relatively large block of text. 2. Trigger the conversion for a complex language like Java or C++. 3. Measure the time taken to complete the conversion and ensure it is reasonable (e.g., a few seconds). - ###### TC6: User Interface Consistency + **Objective**: Verify that the action group and actions maintain consistent UI presentation. + 1. Check that all actions have correct and consistent naming and descriptions as per their language. 2. Ensure that icons (if any) and text formatting are consistent across all instances of the actions. - ##### Post-conditions + - No permanent changes should be made to the project files unless explicitly saved by the tester. - The IDE should remain stable and responsive after testing. - ##### Reporting + - All issues found during testing should be documented with screenshots and detailed replication steps. - Performance metrics should be recorded and analyzed. - Suggestions for improvement or additional test cases should be submitted for review. -This manual test plan will help ensure that the `MarkdownImplementActionGroup` behaves as expected, providing a reliable feature for users to convert text into various programming languages directly within Markdown files. +This manual test plan will help ensure that the `MarkdownImplementActionGroup` behaves as expected, providing a reliable feature for users to convert text into +various programming languages directly within Markdown files. # markdown\MarkdownListAction.kt - #### Manual Test Plan for MarkdownListAction - ##### Objective: -To verify that the `MarkdownListAction` class functions correctly within an IDE environment, specifically focusing on generating and appending new list items to existing markdown lists in a markdown file. +To verify that the `MarkdownListAction` class functions correctly within an IDE environment, specifically focusing on generating and appending new list items to +existing markdown lists in a markdown file. ##### Test Environment: + - IDE (e.g., IntelliJ IDEA) - Java Development Kit (JDK) - Plugin or module containing the `MarkdownListAction` class - Sample markdown files with various list formats - ##### Pre-requisites: + - The plugin/module containing the `MarkdownListAction` is installed and enabled in the IDE. - Open a project that contains at least one markdown file with predefined lists. - ##### Test Cases: - ###### TC1: Basic Functionality Test + **Objective**: Ensure that the action appends new list items correctly to a simple markdown list. + 1. Open a markdown file containing a simple list (e.g., `- Item 1`). 2. Place the cursor within the list. 3. Trigger the `MarkdownListAction`. 4. **Expected Result**: New items are appended to the list, maintaining the same list format. - ###### TC2: Multiple List Types + **Objective**: Verify that the action handles different bullet types correctly. + 1. Open a markdown file containing lists with different bullet types (`-`, `*`, `+`). 2. Place the cursor within each type of list and trigger the action. 3. **Expected Result**: New items should match the bullet type of the existing list. - ###### TC3: Nested Lists + **Objective**: Test the action's ability to handle nested lists. + 1. Open a markdown file with nested lists. 2. Place the cursor in a nested list and trigger the action. 3. **Expected Result**: New items should be added correctly within the nested structure, respecting indentation. - ###### TC4: List with Task Boxes + **Objective**: Ensure the action can handle markdown task lists. + 1. Open a markdown file with a task list (e.g., `- [ ] Task 1`). 2. Place the cursor in the task list and trigger the action. 3. **Expected Result**: New tasks are added with unchecked boxes. - ###### TC5: Empty and Null Item Handling + **Objective**: Verify how the action handles empty or null existing items. + 1. Open a markdown file and create a list with empty items or simulate a scenario where the list API might return null. 2. Trigger the action. 3. **Expected Result**: The action should handle empty/null gracefully, either by ignoring them or by providing a default item text. - ###### TC6: Error Handling + **Objective**: Test the action's robustness in handling errors from the list API. + 1. Simulate an API failure or error response. 2. Trigger the action. 3. **Expected Result**: The action should not crash the IDE and should provide a meaningful error message. - ###### TC7: Performance Test + **Objective**: Ensure that the action performs well with large lists. + 1. Open a markdown file with a very large list (e.g., 100+ items). 2. Trigger the action. 3. **Expected Result**: The action should complete within a reasonable time without performance degradation. - ###### TC8: Undo Functionality + **Objective**: Verify that the undo functionality works after the action is performed. + 1. Perform any of the above test cases. 2. Use the IDE's undo feature. 3. **Expected Result**: The list should revert to its state before the action was triggered. - ##### Post-Conditions: -- After testing, ensure no unwanted changes are saved in the markdown files unless specifically testing save functionality. +- After testing, ensure no unwanted changes are saved in the markdown files unless specifically testing save functionality. ##### Reporting: + - All issues encountered should be documented with screenshots and detailed steps to reproduce. These should be reported to the development team for fixes. This manual test plan will help ensure that the `MarkdownListAction` behaves as expected across different scenarios and markdown list formats. # git\PrintGitCommitPatchAction.kt - #### Manual Test Plan for "Print Git Commit Patch" IntelliJ Plugin Action - ##### Objective: -To verify that the "Print Git Commit Patch" action in the IntelliJ plugin correctly displays the patch information for a selected Git commit. +To verify that the "Print Git Commit Patch" action in the IntelliJ plugin correctly displays the patch information for a selected Git commit. ##### Pre-requisites: + - IntelliJ IDEA must be installed. - The plugin containing the "Print Git Commit Patch" action must be installed and enabled. - A project under Git version control must be opened in IntelliJ IDEA. - ##### Test Environment: + - Operating System: [Specify OS - e.g., Windows 10, macOS Big Sur, etc.] - IntelliJ IDEA Version: [Specify version - e.g., 2021.3] - Plugin Version: [Specify version] - ##### Test Data: -- A Git repository with multiple commits and branches for testing various scenarios. +- A Git repository with multiple commits and branches for testing various scenarios. ##### Test Cases: --- - ###### TC1: Basic Functionality Test + **Objective**: Ensure the action displays the correct patch for a selected commit. **Steps**: + 1. Open a project in IntelliJ that is under Git version control. 2. Right-click on a file in the Project Explorer and select 'Git' -> 'Show History'. 3. In the 'History' tab, select a commit that includes changes to the file. @@ -2574,69 +2865,79 @@ To verify that the "Print Git Commit Patch" action in the IntelliJ plugin correc 5. Observe the output. **Expected Result**: + - A dialog should appear displaying the patch information for the selected commit. --- - ###### TC2: No Commit Selected + **Objective**: Verify the action handles the scenario where no commit is selected. **Steps**: + 1. Open a project in IntelliJ that is under Git version control. 2. Without selecting any commit, invoke the "Print Git Commit Patch" action (via any accessible means, such as a shortcut or command palette). **Expected Result**: + - A dialog should appear with an error message "No commit selected." --- - ###### TC3: No Project Open + **Objective**: Ensure the action is disabled when there is no open project. **Steps**: + 1. Close all projects in IntelliJ. 2. Attempt to invoke the "Print Git Commit Patch" action. **Expected Result**: + - The action should be disabled and not executable. --- - ###### TC4: Multiple Changes in a Single Commit + **Objective**: Verify that the action correctly handles commits with multiple file changes. **Steps**: + 1. Open a project in IntelliJ that is under Git version control. 2. Select a commit from the history that includes multiple file changes. 3. Invoke the "Print Git Commit Patch" action. **Expected Result**: + - The dialog should display patch information for all changed files in the selected commit, separated by clear demarcations. --- - ###### TC5: Action Visibility and Enablement + **Objective**: Confirm that the action is only visible and enabled when a project is open and a revision is selected. **Steps**: + 1. Open a project in IntelliJ and ensure no specific revision is selected. 2. Check the visibility and enablement of the "Print Git Commit Patch" action. **Expected Result**: + - The action should be disabled and possibly hidden if no revision is selected. --- - ##### Post-Test Cleanup: + - Close any open projects in IntelliJ. - Restore any settings changed during testing to their original values. - ##### Reporting: -- Document any discrepancies from the expected results and report them as issues in the issue tracker for the plugin development team to address. Include screenshots and detailed steps to reproduce the issue. + +- Document any discrepancies from the expected results and report them as issues in the issue tracker for the plugin development team to address. Include + screenshots and detailed steps to reproduce the issue. diff --git a/docs/project_info_template.md b/docs/project_info_template.md index 7c666486..3288a34b 100644 --- a/docs/project_info_template.md +++ b/docs/project_info_template.md @@ -18,9 +18,10 @@ Who are the key stakeholders involved in the project? 6. **Assumptions and Context:** - - What assumptions are being made about the project? - - What is the context in which this project is being developed? - - What problem is this project aiming to solve? + +- What assumptions are being made about the project? +- What is the context in which this project is being developed? +- What problem is this project aiming to solve? ## Scope and Deliverables @@ -34,12 +35,14 @@ What is explicitly out of scope for the project? 4. **Use Case Details:** - - What are the primary use cases for the project? - - Provide detailed descriptions of each use case. + +- What are the primary use cases for the project? +- Provide detailed descriptions of each use case. 5. **Comparative Product Analysis:** - - Are there existing products that solve a similar problem? - - How does this project compare to those products? + +- Are there existing products that solve a similar problem? +- How does this project compare to those products? ## Timeline @@ -61,17 +64,20 @@ Identify potential risks and their mitigation strategies. 2. **Assumptions:** - - List any assumptions made during the planning of the project. + +- List any assumptions made during the planning of the project. ## Project Closure 1. **Closure Criteria:** - - What are the criteria for project closure? - - How will success be measured? + +- What are the criteria for project closure? +- How will success be measured? 2. **Post-Implementation Review:** - - Will there be a post-implementation review? - - What will be the focus of this review? + +- Will there be a post-implementation review? +- What will be the focus of this review? 3. **Lessons Learned:** How will lessons learned be documented and shared? @@ -97,42 +103,49 @@ Are there any specific branch naming conventions or commit message guidelines? 6. **Architectural Perspectives:** - - What are the different architectural perspectives of the project? - - Provide diagrams and descriptions for each perspective (e.g., logical, physical, deployment, etc.). - - What coding standards or best practices should be followed? - - Are there any specific linting or formatting tools to be used? - - Are there any version control guidelines? - - Are there any specific branch naming conventions or commit message guidelines? + +- What are the different architectural perspectives of the project? +- Provide diagrams and descriptions for each perspective (e.g., logical, physical, deployment, etc.). +- What coding standards or best practices should be followed? +- Are there any specific linting or formatting tools to be used? +- Are there any version control guidelines? +- Are there any specific branch naming conventions or commit message guidelines? ## Testing and Quality Assurance 1. **Testing Strategy:** - - What is the overall testing strategy? - - What types of testing will be performed (unit, integration, system, acceptance)? + +- What is the overall testing strategy? +- What types of testing will be performed (unit, integration, system, acceptance)? 2. **Test Cases:** Where are the test cases documented? 3. **CI/CD Pipeline:** - - What is the CI/CD pipeline setup? - - What tools and services are used for CI/CD? + +- What is the CI/CD pipeline setup? +- What tools and services are used for CI/CD? 4. **Code Reviews:** - - What is the process for code reviews? - - Who is responsible for code reviews? + +- What is the process for code reviews? +- Who is responsible for code reviews? ## Maintenance and Support 1. **Maintenance Plan:** - - What is the plan for ongoing maintenance? - - How will updates and patches be handled? + +- What is the plan for ongoing maintenance? +- How will updates and patches be handled? 2. **Support Plan:** - - What is the support plan post-deployment? - - Who will provide support and how can they be contacted? + +- What is the support plan post-deployment? +- Who will provide support and how can they be contacted? 3. **Documentation:** - - What user documentation will be provided? - - Where can users find help and support documentation? - - What coding standards or best practices should be followed? - - List any assumptions made during the planning of the project. \ No newline at end of file + +- What user documentation will be provided? +- Where can users find help and support documentation? +- What coding standards or best practices should be followed? +- List any assumptions made during the planning of the project. \ No newline at end of file diff --git a/docs/qa_outline.md b/docs/qa_outline.md index 443dc68d..84c161a5 100644 --- a/docs/qa_outline.md +++ b/docs/qa_outline.md @@ -1,47 +1,75 @@ ## How can I create documents with AI coding? - + -* Basic generation - Code to documentation using "Code Chat" -* Mass generation - Convert many files to documentation using "Generate Docs" -* Aggregation and updating - Edits using "Patch Files" +* Basic generation - Code to documentation using "Code Chat" -+ - Demo: Use the CodeChatAction to generate documentation for a specific code snippet -+ - Highlight how it provides context-aware explanations and can answer follow-up questions -+* Mass generation - Convert many files to documentation using "Generate Docs" -+ - Demo: Use the GenerateDocumentationAction to create documentation for multiple files or an entire project -+ - Show how it handles different file types and maintains consistent documentation style -+* Aggregation and updating - Edits using "Patch Files" -+ - Demo: Use the MassPatchAction to apply consistent changes across multiple files -+ - Demonstrate how it can update existing documentation or add new sections to multiple files simultaneously - * Mermaid diagrams -+ - Demo: Use the CreateImageAction to generate a Mermaid diagram representing code structure or workflow - * Reveal.js presentations -+ - Demo: Use the CreateFileFromDescriptionAction to generate a Reveal.js presentation outline - * Chart.js visualizations -+ - Demo: Use the CreateImageAction to generate a Chart.js visualization based on data in your code - - ## How can I generate projects with AI Coding Assistant? - + ++ + - Demo: Use the CodeChatAction to generate documentation for a specific code snippet ++ + - Highlight how it provides context-aware explanations and can answer follow-up questions + +* Mass generation - Convert many files to documentation using "Generate Docs" ++ + - Demo: Use the GenerateDocumentationAction to create documentation for multiple files or an entire project ++ + - Show how it handles different file types and maintains consistent documentation style + +* Aggregation and updating - Edits using "Patch Files" ++ + - Demo: Use the MassPatchAction to apply consistent changes across multiple files ++ + - Demonstrate how it can update existing documentation or add new sections to multiple files simultaneously + +* Mermaid diagrams + ++ + - Demo: Use the CreateImageAction to generate a Mermaid diagram representing code structure or workflow + +* Reveal.js presentations + ++ + - Demo: Use the CreateFileFromDescriptionAction to generate a Reveal.js presentation outline + +* Chart.js visualizations + ++ + - Demo: Use the CreateImageAction to generate a Chart.js visualization based on data in your code + +## How can I generate projects with AI Coding Assistant? + -* Plan-Ahead action -* Iterative Auto-fixing +* Plan-Ahead action -+ - Demo: Use the PlanAheadAction to break down a complex project into manageable tasks -+ - Show how it generates a step-by-step plan and can execute commands automatically -+* Iterative Auto-fixing -+ - Demo: Use the CommandAutofixAction to run a build or test command and automatically fix issues -+ - Demonstrate how it can iteratively improve code based on command output - - ## How can I make changes to code with AI Coding Assistant? - + ++ + - Demo: Use the PlanAheadAction to break down a complex project into manageable tasks ++ + - Show how it generates a step-by-step plan and can execute commands automatically + +* Iterative Auto-fixing ++ + - Demo: Use the CommandAutofixAction to run a build or test command and automatically fix issues ++ + - Demonstrate how it can iteratively improve code based on command output + +## How can I make changes to code with AI Coding Assistant? + -* Patch Chat -* "Do Something" action +* Patch Chat -+ - Demo: Use the DiffChatAction to discuss and implement changes to your code -+ - Show how it provides a diff view of proposed changes and allows for interactive refinement -+* "Do Something" action -+ - Demo: Use the CustomEditAction to perform a specific code modification task -+ - Highlight how it can handle complex refactoring or feature implementation based on natural language instructions -+* Commit-based actions -+ - Demo: Use the ReplicateCommitAction to apply similar changes from a previous commit to new code -+ - Show how it can adapt past changes to new contexts or requirements - - ## How can I create new AI applications? \ No newline at end of file + ++ + - Demo: Use the DiffChatAction to discuss and implement changes to your code ++ + - Show how it provides a diff view of proposed changes and allows for interactive refinement + +* "Do Something" action ++ + - Demo: Use the CustomEditAction to perform a specific code modification task ++ + - Highlight how it can handle complex refactoring or feature implementation based on natural language instructions + +* Commit-based actions ++ + - Demo: Use the ReplicateCommitAction to apply similar changes from a previous commit to new code ++ + - Show how it can adapt past changes to new contexts or requirements + +## How can I create new AI applications? \ No newline at end of file diff --git a/docs/src/main/kotlin/com/github/simiacryptus/aicoder/actions/data.table.md b/docs/src/main/kotlin/com/github/simiacryptus/aicoder/actions/data.table.md new file mode 100644 index 00000000..6093427c --- /dev/null +++ b/docs/src/main/kotlin/com/github/simiacryptus/aicoder/actions/data.table.md @@ -0,0 +1,25 @@ +| Action Name | Category | Description | Key Features | Requirements | +|-------------------------------|---------------|-----------------------------------------|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------| +| ApplyPatchAction | Code | Applies patch content to selected files | - Multi-file support
- Standard patch format
- Background processing | - Selected files
- Write permissions
- Valid patch content | +| OpenWebPageAction | Navigation | Opens SimiaCryptus website | - Opens default browser
- Fixed URL navigation | - None | +| CustomEditAction | Code | AI-powered code editing | - Multiple language support
- Natural language instructions
- Edit history | - Code selection
- AI model configuration | +| DescribeAction | Documentation | Generates code descriptions | - Language detection
- Comment formatting
- Indentation preservation | - Selected code
- Language recognition | +| PasteAction | Code | Smart clipboard content conversion | - Format detection
- HTML cleanup
- Language conversion | - Valid clipboard content | +| RecentCodeEditsAction | History | Quick access to recent edit commands | - Shows up to 10 commands
- Keyboard shortcuts
- Command history | - Previous edit commands
- Code selection | +| RedoLast | History | Repeats last AI operation | - Background processing
- Session-specific history | - Previous AI action
- Active editor | +| LineFilterChatAction | Chat | Code discussion with line references | - Line number references
- Markdown support
- Persistent sessions | - Developer actions enabled
- API access | +| PrintTreeAction | Development | Prints PSI tree structure | - Async processing
- Progress indication
- Detailed output | - Developer actions enabled
- Valid code selection | +| CreateImageAction | Visualization | Generates code-based images | - Multiple file formats
- Interactive interface
- Auto-saving | - Valid file selection
- AI model settings | +| TestResultAutofixAction | Testing | Analyzes and fixes test failures | - Error analysis
- Diff format fixes
- One-click application | - Failed test selection
- Test framework integration | +| DocumentedMassPatchAction | Code | Updates code based on documentation | - Multi-file processing
- Documentation-driven updates
- Web interface | - Documentation files
- Source files
- AI configuration | +| GenerateDocumentationAction | Documentation | Generates documentation for files | - Batch processing
- Configurable output
- Parallel processing | - Selected files
- Valid project context
- API access | +| GoogleSearchAndDownloadAction | Research | Downloads Google search results | - Automated search
- HTML file saving
- Title sanitization | - Google API key
- Search Engine ID
- Developer actions | +| MarkdownImplementAction | Markdown | Converts text to code blocks | - Multiple language support
- AI code generation
- Markdown formatting | - Markdown file
- Text selection
- AI configuration | +| MultiCodeChatAction | Chat | Multi-file code discussion | - Multiple file support
- Interactive chat
- Code modification | - Selected files
- API access
- Browser support | +| VoiceToTextAction | Input | Speech-to-text dictation | - Real-time transcription
- Context awareness
- Status indication | - Microphone
- Legacy actions enabled
- Audio permissions | +| WebDevelopmentAssistant | Web | Creates web applications | - Architecture design
- File generation
- Asset creation | - Project directory
- Internet connection
- API access | +| DescribeAction | Documentation | Generates code descriptions | - Language detection
- Comment formatting
- Indentation preservation
- AI-powered analysis | - Selected code
- Language recognition
- AI model access | +| LineFilterChatAction | Chat | Code discussion with line references | - Line number references
- Markdown support
- Persistent sessions
- Browser interface | - Developer actions enabled
- API access
- Browser support | +| CreateImageAction | Visualization | Generates code-based images | - Multiple file formats
- Interactive interface
- Auto-saving
- AI image generation | - Valid file selection
- AI model settings
- API access | +| MultiCodeChatAction | Chat | Multi-file code discussion | - Multiple file support
- Interactive chat
- Code modification
- Persistent sessions | - Selected files
- API access
- Browser support
- Project context | +| WebDevelopmentAssistant | Web | Creates web applications | - Architecture design
- File generation
- Asset creation
- Code review | - Project directory
- Internet connection
- API access
- Browser support | \ No newline at end of file diff --git a/docs/src/main/kotlin/com/github/simiacryptus/aicoder/actions/user_documentation.md b/docs/src/main/kotlin/com/github/simiacryptus/aicoder/actions/user_documentation.md new file mode 100644 index 00000000..dd9d3d6c --- /dev/null +++ b/docs/src/main/kotlin/com/github/simiacryptus/aicoder/actions/user_documentation.md @@ -0,0 +1,4383 @@ +# ApplyPatchAction.kt + +Here's the user documentation for the ApplyPatchAction class: + +## Apply Patch Action + +### Overview + +The Apply Patch action allows you to apply patch content to one or more selected files in your project. This is useful when you want to make changes to files +using patch format rather than direct edits. + +### Usage + +1. Select one or more files in your project that you want to apply the patch to +2. Right-click and select "Apply Patch" from the context menu (or use the assigned shortcut if configured) +3. In the dialog that appears, enter or paste the patch content +4. Click OK to apply the patch + +### Details + +- The action will apply the same patch content to all selected files +- The patch should be in a standard patch/diff format +- If the patch cannot be applied cleanly, the operation will fail +- Changes are applied within a write command action to ensure proper undo/redo functionality +- The action runs in the background thread to avoid blocking the UI + +### Requirements + +- One or more files must be selected in the project +- You must have write permissions for the selected files +- The project must be open +- Valid patch content must be provided + +### Tips + +- Make sure your patch content is properly formatted before applying +- Test patches on a backup copy first if you're unsure about the changes +- Use version control to track changes and revert if needed +- The patch dialog supports multiline input for complex patches + +### Error Handling + +The action includes several safeguards: + +- Validates project and file selection +- Requires non-empty patch content +- Executes changes in a write command action for safety +- Changes can be undone using standard IDE undo functionality + +# OpenWebPageAction.kt + +Here's the documentation for the OpenWebPageAction class: + +## OpenWebPageAction + +A simple action that opens a specific web page in the user's default browser. + +### Overview + +`OpenWebPageAction` is an IntelliJ IDEA plugin action that opens the SimiaCryptus applications website (http://apps.simiacrypt.us/) when triggered. + +### Usage + +This action can be triggered from anywhere within the IDE where actions are available (menus, toolbars, etc.). When activated, it will: + +1. Open the user's default web browser +2. Navigate to http://apps.simiacrypt.us/ + +### Technical Details + +- Extends `AnAction` from the IntelliJ Platform SDK +- Uses the `BrowseUtil.browse()` utility method to handle browser opening +- No configuration required - the URL is hardcoded + +### Implementation + +The action is implemented as a simple override of `actionPerformed()` that calls the browse utility with a fixed URI. + +### Dependencies + +- Requires `com.simiacryptus.aicoder.util.BrowseUtil` for browser handling +- Uses Java's `URI` class for URL representation + +### Example + +```kotlin +// The action will be triggered automatically by the IDE when the user activates it +val action = OpenWebPageAction() +``` + +# code\CustomEditAction.kt + +Here's the user documentation for the CustomEditAction class: + +## Custom Edit Action + +The Custom Edit Action allows you to perform AI-powered custom edits on selected code in your IDE. This action provides a flexible way to modify code using +natural language instructions. + +### Features + +- Supports editing code in multiple programming languages +- Uses AI to interpret and apply custom editing instructions +- Preserves code context and language-specific formatting +- Maintains edit history for reuse of common instructions + +### Usage + +1. Select the code you want to edit in the editor +2. Trigger the Custom Edit action (via menu or shortcut) +3. Enter your editing instruction in the dialog that appears +4. The AI will process your instruction and apply the changes to the selected code + +### Examples of Edit Instructions + +- "Add documentation comments" +- "Optimize this code for performance" +- "Convert this loop to use streams" +- "Add error handling" +- "Refactor to follow clean code principles" + +### Technical Details + +- The action uses the configured AI model from your settings +- Editing temperature can be adjusted in settings to control creativity/consistency +- Supports the human language specified in your settings +- Previous edit instructions are saved in history for quick reuse + +### Error Handling + +- If an error occurs during processing, an error dialog will be shown +- The original code selection is preserved if the edit fails +- Errors are logged for troubleshooting + +### Configuration + +The action uses several settings from AppSettingsState: + +- AI model selection +- Temperature setting +- Human language preference +- Edit history management + +### Tips + +- Be specific in your edit instructions for best results +- Use language-appropriate terminology in your instructions +- Review the changes before accepting them +- Use the edit history to reuse successful instructions + +# code\DescribeAction.kt + +Here's the user documentation for the DescribeAction class: + +## DescribeAction Documentation + +### Overview + +The DescribeAction is an IntelliJ IDEA plugin action that generates natural language descriptions of selected code snippets. It helps developers understand code +by providing human-readable explanations of what the code does. + +### Features + +- Automatically detects the programming language of the selected code +- Generates descriptions in the user's configured human language +- Formats the description as appropriate code comments (line or block comments) +- Preserves code indentation +- Works with any programming language supported by IntelliJ IDEA + +### Usage + +1. Select a block of code in the editor that you want to describe +2. Invoke the action through: + +- The context menu (right-click) +- A keyboard shortcut (if configured) +- The Actions menu + +The action will: + +1. Analyze the selected code +2. Generate a natural language description +3. Insert the description as a comment above the selected code +4. Preserve the original code indentation and formatting + +### Requirements + +- The action only works when there is text selected in the editor +- The file's programming language should be recognized by IntelliJ IDEA for optimal comment formatting + +### Configuration + +The action uses these settings from the plugin configuration: + +- Human Language: The language used for generating descriptions +- Temperature: Controls the creativity/randomness of the generated descriptions +- Model: The AI model used for generating descriptions + +### Example + +```java +// This method calculates the factorial of a given number using recursion +public int factorial(int n) { + if (n <= 1) return 1; + return n * factorial(n-1); +} +``` + +### Notes + +- The description format (line vs. block comments) is automatically chosen based on the length of the generated description +- Single-line descriptions use line comments +- Multi-line descriptions use block comments +- If the programming language is not recognized, the description will be inserted without comment formatting + +### Error Handling + +If an error occurs during description generation, an error message will be logged and the exception will be propagated to the user interface. + +# code\PasteAction.kt + +Here's the user documentation for the PasteAction code: + +## Smart Paste Actions Documentation + +### Overview + +The Smart Paste functionality provides enhanced clipboard paste operations that automatically detect and convert content between different formats and +programming languages. There are two variants available: + +- **Smart Paste**: Uses a more sophisticated AI model for higher quality conversions +- **Fast Paste**: Uses a simpler, faster AI model for quicker conversions + +### Features + +#### Clipboard Content Support + +- Plain text +- HTML content (with automatic cleanup) +- Code snippets +- Rich text + +#### Key Capabilities + +- Automatic language detection of source content +- Conversion to target language/format based on current file type +- HTML content optimization and cleanup +- Support for all programming languages +- Preserves important formatting and structure + +### Usage + +1. Copy content to your clipboard from any source +2. Place cursor at desired paste location in editor +3. Use one of the paste actions: + +- Smart Paste: For highest quality conversion +- Fast Paste: For quicker conversion of simpler content + +The action will automatically: + +1. Detect the content type and format +2. Clean up HTML if present +3. Convert to appropriate format for current file +4. Insert the converted content at cursor location + +### Supported Scenarios + +- Converting between programming languages +- Pasting HTML content as code +- Formatting text content to match current file +- Cleaning up and normalizing code snippets + +### Notes + +- Smart Paste provides better results but may be slower +- Fast Paste is optimized for speed but may produce simpler conversions +- HTML content is automatically cleaned and optimized before conversion +- The action is only enabled when valid content is available in clipboard +- Conversion quality depends on source content format and complexity + +### Error Handling + +- Invalid clipboard content will be ignored +- Conversion failures will be logged +- Maximum content size limits prevent processing extremely large content +- Malformed HTML will be automatically repaired when possible + +The paste actions aim to provide seamless conversion of clipboard content while maintaining code quality and formatting standards of the target file. + +# code\RecentCodeEditsAction.kt + +Here's the user documentation for the RecentCodeEditsAction class: + +## Recent Code Edits Action + +The Recent Code Edits action provides quick access to your most recently used custom code edit commands through a dropdown menu in the IDE. + +### Features + +- Displays up to 10 of your most recently used custom edit commands +- Keyboard shortcuts for quick access (1-9 for first 9 items) +- Each menu item shows the command text and executes it on the current selection +- Only enabled when code is selected (not plain text) + +### Usage + +1. Select some code in the editor +2. Click the Recent Code Edits action button or use its shortcut +3. Choose a recent command from the dropdown menu: + +- Use number keys 1-9 for quick access to first 9 items +- Click any item to execute that command +- Commands are shown with most recent first + +### Requirements + +- Must have text selected in the editor +- Selected text must be in a programming language file (not plain text) +- Must have previously used custom edit commands to populate the history + +### Technical Details + +- Commands are stored in the application settings under "customEdits" +- Up to 10 most recent unique commands are shown +- Menu items are numbered from 1-10 for reference +- Each menu item executes the command using CustomEditAction functionality + +### Related Features + +- CustomEditAction - For creating new custom edit commands +- AppSettingsState - Stores command history +- UITools - Handles selection state + +This action helps improve productivity by providing quick access to your frequently used custom edit commands without having to retype them. + +# code\RedoLast.kt + +Here's the user documentation for the RedoLast action: + +## RedoLast Action + +### Overview + +The RedoLast action allows you to repeat the most recent AI Coder operation that was performed in your editor. This is useful when you want to apply the same +AI-powered modification again without having to reconfigure the action. + +### Usage + +#### How to Access + +You can access the RedoLast action in several ways: + +1. Through the editor context menu (right-click menu) +2. Using the assigned keyboard shortcut (if configured) +3. Via the AI Coder actions menu + +#### Prerequisites + +- An active editor window must be open +- At least one previous AI Coder action must have been performed in the current editor session + +#### Steps + +1. Position your cursor in the editor where you want to redo the last action +2. Trigger the RedoLast action using one of the access methods mentioned above +3. The last AI Coder action will be automatically repeated at the current location + +### Behavior + +- The action will only be enabled if there is a previous AI Coder action available to redo +- The action operates on the current editor document +- The redo operation runs in the background to avoid blocking the UI + +### Limitations + +- Only the most recent AI Coder action can be redone +- The action state is specific to each editor document +- The redo history is not preserved between IDE sessions + +### Tips + +- Use this feature to quickly apply repetitive AI-powered modifications +- The action is particularly useful when you need to apply the same AI transformation to different parts of your code + +### Related Features + +- Other AI Coder editing actions +- Standard IDE undo/redo operations (these are separate from the AI Coder redo functionality) + +# dev\LineFilterChatAction.kt + +Here's the user documentation for the LineFilterChatAction: + +## Line Filter Chat Action + +The Line Filter Chat Action provides an interactive way to discuss and analyze code with an AI assistant, with special support for referencing specific lines of +code. + +### Overview + +This action opens a chat interface where you can discuss code with an AI assistant. The assistant has access to the full context of your selected code or file, +and can reference specific line numbers in its responses. + +### Usage + +1. Select code in the editor (optional - if no selection is made, the entire file will be used) +2. Invoke the action through: + +- Search actions (Ctrl+Shift+A / ⌘⇧A) and search for "Line Filter Chat" +- Or through any configured keyboard shortcuts + +A browser window will open with a chat interface where you can: + +- Ask questions about the code +- Request explanations +- Get suggestions for improvements +- Reference specific lines by their number + +### Features + +- **Line Number References**: The AI can reference specific lines of code using line numbers, making discussions more precise +- **Code Context**: The AI has full context of your code file including: + - File name + - Programming language + - Complete code content +- **Markdown Support**: Responses are formatted in Markdown for better readability +- **Persistent Sessions**: Chat sessions are saved and can be referenced later + +### Example Usage + +You can ask questions like: + +- "Can you explain what lines 10-15 do?" +- "Is there a better way to implement the function at line 25?" +- "What's the purpose of the variable defined on line 8?" + +The AI will respond with explanations that can include direct line references and formatted code blocks. + +### Notes + +- This feature is only available when developer actions are enabled in the plugin settings +- The chat interface opens in your default web browser +- Sessions are automatically named with a timestamp for easy reference + +### Requirements + +- Plugin must be properly configured with API access +- Developer actions must be enabled in plugin settings +- A working internet connection for AI communication + +# dev\PrintTreeAction.kt + +Here's the user documentation for the PrintTreeAction class: + +## PrintTreeAction Documentation + +### Overview + +PrintTreeAction is a developer utility action in IntelliJ that allows you to print the PSI (Program Structure Interface) tree structure of the currently +selected code or file. This is particularly useful for developers who need to understand or debug the internal representation of code within the IntelliJ +platform. + +### Prerequisites + +- The "Developer Actions" feature must be enabled in the plugin settings +- An open file or selected code in the IntelliJ editor + +### How to Use + +1. **Enable Developer Actions** + +- Go to Settings/Preferences +- Navigate to the AI Coder plugin settings +- Enable the "Developer Actions" option + +2. **Access the Action** + +- Right-click in the editor to open the context menu +- Look for the "Print Tree" action + +3. **View Results** + +- The PSI tree structure will be printed to the IDE's log +- You can view the output in the IDE's log window or console + +### Features + +- Prints detailed PSI tree structure of selected code +- Runs asynchronously to prevent UI freezing +- Provides progress indication during analysis +- Includes error handling and logging + +### Common Use Cases + +- Debugging code structure issues +- Understanding how IntelliJ parses your code +- Investigating PSI-related problems +- Learning about code structure representation + +### Troubleshooting + +If you encounter issues: + +- Verify that "Developer Actions" is enabled +- Ensure you have valid code selected +- Check the IDE's log for error messages +- Make sure you have appropriate file permissions + +### Notes + +- The action only works when there is a valid PSI entity in the current context +- The operation runs in the background to maintain IDE responsiveness +- Output is logged at INFO level for successful operations and WARN level for issues + +# generic\BaseAction.kt + +Here's the documentation for the BaseAction class: + +## BaseAction Class Documentation + +`BaseAction` is an abstract base class that provides common functionality for IntelliJ IDEA plugin actions. It extends `AnAction` and includes utility methods +for error handling and write operations. + +### Properties + +- `api: ChatClient` - A lazy-initialized ChatClient instance used for API communications + +### Methods + +#### showError + +```kotlin +protected fun showError(project: Project?, message: String) +``` + +Displays an error dialog to the user. + +- Parameters: + - `project`: The current project context (can be null) + - `message`: The error message to display + +#### showWarning + +```kotlin +protected fun showWarning(project: Project?, message: String) +``` + +Displays a warning dialog to the user. + +- Parameters: + - `project`: The current project context (can be null) + - `message`: The warning message to display + +#### runWriteAction + +```kotlin +protected fun runWriteAction(project: Project, action: () -> Unit) +``` + +Executes code that modifies the project/documents within a write action context. + +- Parameters: + - `project`: The current project context + - `action`: Lambda containing the code to execute + +### Usage + +Extend this class to create new plugin actions that need: + +- Error/warning dialogs +- Write access to documents +- Chat API functionality + +Example: + +```kotlin +class MyAction : BaseAction() { + override fun actionPerformed(e: AnActionEvent) { + val project = e.project + try { + runWriteAction(project) { + // Perform document modifications + } + } catch (ex: Exception) { + showError(project, "Failed to perform action: ${ex.message}") + } + } +} +``` + +The base class handles common boilerplate code and provides a consistent way to handle errors and document modifications across different actions. + +# generic\CodeChatAction.kt + +Here's the user documentation for the CodeChatAction class: + +## Code Chat Action + +The Code Chat Action provides an interactive chat interface for discussing and working with code selections or entire files in your IDE. + +### Overview + +This action opens a web-based chat interface that allows you to have an AI-assisted conversation about your code. It's useful for: + +- Getting explanations about code +- Discussing potential improvements +- Asking questions about implementation details +- Getting suggestions for modifications + +### Usage + +1. Select code in the editor (optional - if no selection is made, the entire file will be used) +2. Trigger the Code Chat action through: + +- The IDE menu +- A keyboard shortcut (if configured) +- The context menu + +A browser window will automatically open with the chat interface where you can: + +- Type messages to discuss the code +- See the AI's responses +- Have a continuous conversation about the code + +### Features + +- **Language-Aware**: Automatically detects the programming language of your code +- **Persistent Sessions**: Chat sessions are preserved and can be referenced later +- **Real-time Interaction**: Immediate responses through WebSocket communication +- **Context-Aware**: Maintains awareness of the file name and code context throughout the conversation + +### Technical Details + +- Uses the configured smart model from your settings +- Creates a unique session ID for each chat instance +- Stores chat history in your configured plugin home directory +- Runs the chat server locally through your IDE + +### Requirements + +- Active internet connection +- Properly configured API credentials in the plugin settings +- A modern web browser for the chat interface + +### Notes + +- The chat session will be named with the format "CodeChatAction @ HH:mm:ss" +- You can have multiple chat sessions open simultaneously +- The browser window should open automatically, but you may need to allow pop-ups + +# generic\CommandAutofixAction.kt + +Here's the user documentation for the CommandAutofixAction class: + +## Command Autofix Action + +The Command Autofix Action is a tool that helps automatically fix issues reported by command-line tools and build processes. It executes a specified command and +uses AI to analyze and fix any errors or issues that occur. + +### Features + +- Execute any command-line tool or build process +- Automatically detect and analyze command output +- AI-powered suggestions for fixing issues +- Optional auto-apply fixes +- Configurable working directory and arguments +- Support for different exit code handling strategies + +### Usage + +1. Right-click on a folder or file in your project +2. Select "Command Autofix" from the context menu +3. Configure the command settings in the dialog: + +#### Settings Dialog Options + +- **Executable**: Select or browse for the command/program to run +- **Arguments**: Enter command-line arguments (e.g. "run build") +- **Working Directory**: Set the directory where the command will execute +- **Exit Code Options**: + - Patch nonzero exit code: Only fix when command fails + - Patch 0 exit code: Fix when command succeeds + - Patch any exit code: Always attempt fixes +- **Additional Instructions**: Provide custom instructions for the AI +- **Auto-apply fixes**: Automatically apply suggested fixes without confirmation + +4. Click OK to run the command +5. A browser window will open showing: + +- Command output +- Detected issues +- Suggested fixes +- Options to apply/modify fixes + +### Tips + +- The tool remembers recently used commands and arguments +- You can select specific files/folders to limit the scope +- Additional instructions help guide the AI's fix suggestions +- Auto-fix mode is useful for routine/known issues +- The working directory defaults to the selected folder or project root + +### Requirements + +- Project must be open in the IDE +- Selected folder or project base path must be accessible +- Specified command must be executable from the working directory + +### Notes + +- Fix suggestions are AI-generated and should be reviewed +- Complex build issues may require manual intervention +- Command history is preserved between sessions +- Browser interface provides interactive fix management + +This tool is ideal for automating fixes for common build errors, linting issues, and other command-line tool outputs. + +# generic\CreateFileFromDescriptionAction.kt + +Here's the user documentation for the CreateFileFromDescriptionAction: + +## Create File From Description Action + +### Overview + +The Create File From Description action allows you to generate new files in your project using natural language descriptions. This feature leverages AI to +interpret your requirements and create appropriate file content. + +### Usage + +1. Right-click in the project explorer or editor where you want to create a new file +2. Select "Create File From Description" from the context menu +3. In the dialog that appears, enter your description of the file you want to create +4. Click OK to generate the file + +### Description Format + +The description should include: + +- What type of file you want to create +- The intended purpose or functionality +- Any specific requirements or features needed + +Example descriptions: + +``` +Create a new React component for a login form with email and password fields +``` + +``` +Create a Python utility class for handling file operations like read, write and append +``` + +### File Location + +- The new file will be created relative to your currently selected location in the project +- If a file with the same name already exists, a numbered suffix will be added automatically +- The AI will suggest an appropriate file name and location based on standard conventions + +### Notes + +- The generated file content can be modified after creation if needed +- The action uses AI to interpret requirements, so being clear and specific in your description will yield better results +- File paths are automatically handled to ensure they are valid within your project structure + +### Error Handling + +- If file generation fails, an error dialog will be shown with details +- Common issues include: + - Empty/invalid descriptions + - Network/API connectivity problems + - Permission issues when writing files + +### Tips + +- Include relevant technical details in your description for more accurate results +- Review the generated file content to ensure it meets your requirements +- The action works best with clear, focused descriptions of a single file's purpose + +# generic\CreateImageAction.kt + +Here's the user documentation for the CreateImageAction class: + +## Create Image Action + +### Overview + +The Create Image Action is a feature that generates technical drawings or visual representations based on your code files. It uses AI to analyze your code and +create relevant images that can help visualize the code structure, architecture, or concepts. + +### Features + +- Generates images based on selected code files or directories +- Supports multiple file formats (PNG and JPG) +- Interactive chat interface for customizing image generation +- Automatically saves generated images to your project directory + +### Supported File Types + +The action works with the following file extensions: + +- Kotlin (.kt) +- Java (.java) +- Python (.py) +- JavaScript (.js) +- TypeScript (.ts) +- HTML (.html) +- CSS (.css) +- XML (.xml) + +### How to Use + +1. **Select Content** + +- Select one or more files in your project explorer +- Or select a directory to analyze multiple files at once + +2. **Invoke the Action** + +- Right-click on your selection +- Find "Create Image" in the context menu +- Or use the assigned keyboard shortcut if configured + +3. **Interact with the Generator** + +- A browser window will open with a chat interface +- Describe what kind of visualization you want +- The AI will generate images based on your code and requirements + +4. **View and Save Results** + +- Generated images will be displayed in the chat interface +- Images are automatically saved in both PNG and JPG formats +- Files are saved in your project directory with randomly generated names + +### Technical Details + +- Images are generated using AI models configured in your application settings +- Default image size is 1024x1024 pixels +- Generated files are saved with unique UUIDs as filenames +- The system creates a summary of your code files before generating images + +### Troubleshooting + +If you encounter issues: + +- Ensure you have selected valid file types +- Check that your project directory is writable +- Verify your AI model settings in the application configuration +- Look for error messages in the IDE's event log + +### Requirements + +- Active project in the IDE +- Valid file selection +- Proper configuration of AI model settings +- Internet connection for AI model access + +# generic\DiffChatAction.kt + +Here's the user documentation for the DiffChatAction class: + +## DiffChat Action + +The DiffChat action provides an interactive chat interface for making code modifications using a diff-based format. It allows users to discuss and apply code +changes through a chat interface while maintaining precise control over the modifications. + +### Features + +- Interactive chat interface for code modifications +- Diff-based format for clear visualization of changes +- Supports both selected code and entire files +- Automatic language detection +- One-click application of suggested changes +- Context-aware modifications + +### Usage + +1. **Accessing the Action** + +- Select code in the editor (optional - if no selection is made, the entire file will be used) +- Right-click to open the context menu +- Select "DiffChat" from the available actions + +2. **Chat Interface** + +- A browser window will open with the chat interface +- The selected code or file content will be available as context +- You can discuss modifications with the AI assistant + +3. **Applying Changes** + +- Changes will be suggested in a diff format showing: + - Lines to be removed (prefixed with `-`) + - Lines to be added (prefixed with `+`) + - Context lines around the changes +- Click the "Apply" link next to a diff block to apply those specific changes + +### Example Interaction + +``` +User: "Can you optimize this code for better performance?" + +# generic\DocumentedMassPatchAction.kt + +Here's the user documentation for the DocumentedMassPatchAction class: + + +## Documented Mass Patch Action + +The Documented Mass Patch Action is a tool that helps you automatically review and update code files according to documentation standards by analyzing both documentation and source code files together. + + +### Features + +- Select multiple documentation (.md) files and source code files for analysis +- Provide custom AI instructions for code review and updates +- Option to automatically apply suggested changes +- Web-based interface for reviewing changes +- Integration with project documentation standards + + +### Usage + +1. Right-click in the project explorer to launch the Documented Mass Patch action + +2. In the configuration dialog: + - Select relevant documentation files (.md) that contain standards/requirements + - Select source code files to be reviewed/updated + - Enter AI instructions for how the code should be analyzed and modified + - Optionally enable "Auto Apply Changes" to automatically implement suggestions + - Click OK to proceed + +3. A browser window will open showing: + - The selected files and their contents + - AI analysis and suggested changes + - Options to review and apply changes + +4. Review the suggested changes and: + - Accept/reject individual changes + - Apply all approved changes + - Add comments or additional instructions + + +### Configuration Options + +- **Documentation Files**: Select .md files containing documentation standards, requirements, or guidelines +- **Code Files**: Select source code files to be analyzed and potentially modified +- **AI Instruction**: Custom instructions for how the code should be reviewed/updated +- **Auto Apply**: Toggle automatic application of suggested changes + + +### Best Practices + +1. Start with a small set of files for initial testing +2. Provide clear, specific AI instructions +3. Review all suggested changes carefully before applying +4. Keep documentation files focused and relevant to the code being modified +5. Use version control to track changes + + +### Technical Details + +- Supports any text-based source code files +- Markdown (.md) files are used for documentation input +- Changes are made through a diff-based patch system +- Web interface runs on local server for security +- Session-based to support multiple concurrent operations + + +### Notes + +- Large file sets may take longer to process +- Auto-apply should be used cautiously on critical code +- All changes can be reviewed before final application +- The tool respects project-specific file exclusions + +This tool is ideal for ensuring code compliance with documentation standards, implementing coding standards across multiple files, and maintaining consistency between documentation and implementation. + +# generic\DocumentedMassPatchServer.kt + +Here's the user documentation for the DocumentedMassPatchServer class: + + +## DocumentedMassPatchServer + +The DocumentedMassPatchServer is a server component that handles automated code review and patch generation based on documentation files and code files. + + +### Overview + +This server facilitates: +- Reviewing code files against documentation requirements +- Generating suggested code improvements as patches +- Providing an interactive interface for reviewing and applying patches + + +### Key Features + +- Processes multiple code files in parallel +- Compares code against documentation files +- Generates patches in standard diff format +- Optional automatic patch application +- Interactive web interface with tabbed display +- Logging of API interactions + + +### Configuration + +The server requires: + +1. `DocumentedMassPatchAction.Settings` containing: + - Project configuration + - Documentation file paths + - Code file paths + - Transformation message (optional) + +2. `ChatClient` for AI interactions + +3. `autoApply` flag to control automatic patch application + + +### Usage + +1. The server processes each code file against the documentation: + - Documentation files are read and combined + - Each code file is analyzed in context of the documentation + - AI generates suggested improvements as patches + +2. For each file, the server: + - Creates a new tab in the interface + - Displays the analysis and suggested patches + - Provides links to apply patches if approved + - Logs the process and any errors + +3. Patches are presented in standard diff format: + - `+` indicates line additions + - `-` indicates line deletions + - Context lines are included before and after changes + + +### Interface + +The web interface provides: +- Tabbed display for multiple files +- Markdown rendering of suggestions +- Interactive links for applying patches +- Progress tracking and error reporting +- API logging for debugging + + +### Error Handling + +- Errors during file processing are logged and displayed in the UI +- Each file is processed independently to prevent total failure +- API interactions are logged for troubleshooting + + +### Technical Details + +- Uses a semaphore-based discussion system +- Supports concurrent file processing +- Integrates with IDE file system +- Configurable AI model settings +- Extensible through the ApplicationServer framework + +# generic\EnhancedChatSocketManager.kt + +Here's the user documentation for the EnhancedChatSocketManager class: + + +## EnhancedChatSocketManager + +The EnhancedChatSocketManager is an enhanced version of the ChatSocketManager that provides support for handling large output responses in chat interactions. + + +### Overview + +This class extends the base ChatSocketManager to integrate with a LargeOutputActor, enabling better handling of lengthy responses from the language model. + + +### Constructor Parameters + +- `session`: The Session object managing the current user session +- `model`: The ChatModel to be used for generating responses +- `userInterfacePrompt`: The prompt displayed to users in the interface +- `systemPrompt`: The system-level prompt that guides the model's behavior +- `api`: The ChatClient instance for communicating with the language model API +- `storage`: Optional StorageInterface for persisting chat data +- `applicationClass`: The ApplicationServer class type +- `largeOutputActor`: LargeOutputActor instance for handling large response generation + + +### Key Features + +- Extends standard chat socket management functionality +- Integrates with LargeOutputActor for handling large responses +- Provides robust error handling for empty responses +- Maintains compatibility with base ChatSocketManager features + + +### Usage Example + +```kotlin +val enhancedManager = EnhancedChatSocketManager( + session = currentSession, + model = selectedModel, + userInterfacePrompt = "How can I help you?", + systemPrompt = "You are a helpful assistant", + api = chatClient, + storage = dataStorage, + applicationClass = MyAppServer::class.java, + largeOutputActor = LargeOutputActor(...) +) +``` + +### Error Handling + +The class will throw a RuntimeException if the language model returns an empty or null response. + +### Dependencies + +- Requires jopenai library for API communication +- Depends on skyenet-core and skyenet-webui components +- Needs a properly configured LargeOutputActor instance + +This documentation provides an overview of the EnhancedChatSocketManager class and its key functionality for developers integrating chat capabilities with +support for large outputs in their applications. + +# generic\GenerateDocumentationAction.kt + +## GenerateDocumentationAction Documentation + +This class provides functionality to generate documentation for files in a project using AI assistance. Here's a comprehensive overview of its features and +usage: + +### Overview + +`GenerateDocumentationAction` is a Kotlin class that extends `FileContextAction` and provides an interface for generating documentation from source files using +AI-powered content transformation. + +### Key Features + +1. **Batch Documentation Generation** + +- Can process multiple files simultaneously +- Supports both single-file and multi-file output modes +- Uses parallel processing for improved performance + +2. **Configurable Output** + +- Option to generate a single consolidated documentation file +- Support for custom output directory structure +- Automatic file naming with conflict resolution + +3. **User Interface** + +- Interactive dialog for configuration +- File selection checklist +- Recent instructions history +- Customizable AI instructions +- Output path configuration + +### How to Use + +1. **Launch the Action** + +- Select a directory in your project +- Right-click and select the documentation generation action + +2. **Configure Settings** + +- Choose files to process using the checkbox list +- Enter or select an AI instruction for documentation generation +- Specify output filename and directory +- Toggle single/multiple output file mode + +3. **Output Options** + +- Single File Mode: Generates one consolidated markdown file +- Multiple File Mode: Creates individual documentation files for each source file + +### Configuration Options + +- **Single Output File**: Toggle to combine all documentation into one file +- **Files to Process**: Select specific files for documentation +- **AI Instruction**: Custom instructions for the AI documentation generator +- **Output File**: Name of the output documentation file +- **Output Directory**: Target directory for generated documentation + +### Error Handling + +- Includes retry mechanism for failed file processing +- Timeout protection for long-running operations +- Validation for required input fields +- Automatic backup naming for existing files + +### Technical Details + +- Uses concurrent processing with configurable thread pool +- Supports Git repository structure awareness +- Integrates with IntelliJ's file system and editor +- Maintains history of recent documentation instructions + +### Best Practices + +1. **AI Instructions** + +- Be specific about the documentation style needed +- Consider the target audience +- Include any special formatting requirements + +2. **File Selection** + +- Group related files for consistent documentation +- Consider dependencies between files +- Exclude generated or binary files + +3. **Output Organization** + +- Use meaningful file names +- Maintain a consistent directory structure +- Consider using the single-file mode for related components + +### Limitations + +- Requires valid project context +- Cannot process directories directly +- May have timeout limitations for very large files +- Requires network connectivity for AI processing + +This documentation generator is particularly useful for maintaining up-to-date documentation for code bases and ensuring consistency across project +documentation. + +# generic\GenerateRelatedFileAction.kt + +Here's the user documentation for the GenerateRelatedFileAction class: + +## Generate Related File Action + +The Generate Related File action helps you automatically create related files (like test cases, implementations, or companion files) based on an existing source +file using AI assistance. + +### Usage + +1. Select a single file in your project +2. Right-click and select "Generate Related File" from the context menu (or use the assigned shortcut if configured) +3. In the dialog that appears: + +- Enter your directive describing what kind of file you want to generate (e.g., "Create test cases", "Generate interface", etc.) +- Click OK to proceed + +### Features + +- Automatically generates a new file based on the selected source file and your directive +- Uses AI to analyze the source file and create appropriate related content +- Automatically determines appropriate file naming and placement +- Handles file naming conflicts by adding numerical suffixes +- Opens the generated file automatically in the editor + +### Configuration + +The action uses the following settings from your IDE configuration: + +- AI model selection (uses the configured "smart model") +- Temperature setting for AI generation +- API credentials and settings + +### Examples + +Some example use cases: + +- Generate unit tests for a class +- Create an interface from an implementation +- Generate a companion class +- Create documentation files +- Generate mock implementations + +### Notes + +- Works on single file selection only +- Generated files are placed relative to the project root +- If a file with the target name already exists, a numbered suffix will be added +- The action requires proper API configuration in the IDE settings + +### Troubleshooting + +If you encounter issues: + +- Ensure you have selected only one file +- Verify your API credentials are configured correctly +- Check the IDE's event log for any error messages +- Make sure you have write permissions in the target directory + +The action will automatically handle file system refreshing and opening the new file in the editor once generation is complete. + +# generic\GenericChatAction.kt + +Here's the user documentation for the GenericChatAction class: + +## Generic Chat Action + +The Generic Chat Action provides a simple way to initiate an AI-powered chat session within the IDE. This action opens a browser-based chat interface that +allows you to have natural language conversations with an AI assistant. + +### Features + +- Opens a dedicated chat window in your default web browser +- Uses the configured smart model from your application settings +- Creates a unique session for each chat instance +- Timestamps each chat session for easy reference +- Provides a persistent chat interface for ongoing conversations + +### Usage + +1. You can trigger the Generic Chat Action through: + +- The IDE's action menu +- Keyboard shortcuts (if configured) +- The IDE's search actions (Ctrl+Shift+A / ⌘⇧A) + +2. When activated: + +- A new chat session will be initialized +- Your default browser will open automatically +- The chat interface will be ready for interaction + +### Requirements + +- An active project must be open in the IDE +- Valid API configuration in the application settings +- A working internet connection for AI model access + +### Technical Details + +- Uses the smart model configured in AppSettingsState +- Creates a unique session ID for each chat instance +- Runs asynchronously to prevent UI freezing +- Integrates with the IDE's project system + +### Troubleshooting + +If you encounter issues: + +- Check your internet connection +- Verify your API configuration in the application settings +- Ensure your browser is not blocking pop-ups from the IDE +- Check the IDE's log for any error messages + +### Notes + +- Chat sessions are preserved until the IDE is closed +- Each chat session is labeled with a timestamp for easy identification +- The chat interface runs in your default web browser but communicates with the IDE + +This action is ideal for general-purpose AI assistance and code-related discussions without requiring specific code context. + +# generic\LargeOutputChatAction.kt + +Here's the user documentation for the LargeOutputChatAction class: + +## Enhanced Code Chat Action + +The Enhanced Code Chat action provides an advanced chat interface optimized for handling large, complex coding discussions and explanations. + +### Features + +- Structured responses that break down complex information into clear sections +- Enhanced formatting using ellipsis notation for better readability +- Persistent chat sessions with timestamped names +- Browser-based interface for comfortable interaction +- Support for detailed code explanations and discussions + +### Usage + +1. Trigger the Enhanced Code Chat action from your IDE +2. A new browser window will open automatically with the chat interface +3. Enter your coding questions or requests in the chat input +4. Receive well-structured, detailed responses broken down into clear sections + +### Key Benefits + +- **Better Organization**: Complex explanations are automatically structured into digestible sections +- **Persistent Sessions**: Chat sessions are saved and can be referenced later +- **User-Friendly Interface**: Clean browser-based UI for comfortable interaction +- **Smart Response Generation**: Uses advanced AI model to provide detailed, relevant answers +- **Optimized for Code**: Specifically designed for programming-related discussions + +### Technical Details + +- Uses OpenAI's chat model for response generation +- Temperature setting of 0.3 for balanced creativity and accuracy +- Maximum of 3 iterations per response for optimal results +- Integrated with IDE's project context +- Sessions are uniquely identified and timestamped + +### Notes + +- Internet connection required for functionality +- Chat sessions are preserved in the plugin's home directory +- Browser access is required for the interface + +The Enhanced Code Chat action is particularly useful for: + +- Getting detailed code explanations +- Breaking down complex programming concepts +- Receiving structured coding advice +- Maintaining organized coding discussions + +# generic\MassPatchAction.kt + +Here's the documentation for the MassPatchAction and MassPatchServer classes: + +## MassPatchAction Documentation + +### Overview + +MassPatchAction is an IntelliJ IDEA plugin action that allows batch processing and modification of multiple files using AI-powered suggestions. It provides a +user interface for selecting files and specifying transformation instructions. + +### Key Features + +#### File Selection + +- Allows selecting multiple files or folders to process +- Automatically filters for compatible file types +- Provides a checkbox list interface for fine-grained file selection + +#### Transformation Configuration + +- Supports custom AI instructions for code transformation +- Maintains history of recent instructions for quick reuse +- Optional auto-apply setting for automatic patch application + +#### User Interface + +- Dialog-based configuration with: + - File selection checklist + - Instruction input area + - Recent instructions dropdown + - Auto-apply toggle + +### Usage + +1. Select files/folders in the project explorer +2. Invoke the MassPatchAction +3. In the configuration dialog: + +- Select files to process +- Enter transformation instructions or select from recent ones +- Optionally enable auto-apply + +4. Click OK to start processing +5. Review and apply suggested changes in the browser interface + +## MassPatchServer Documentation + +### Overview + +MassPatchServer handles the backend processing for MassPatchAction, managing the AI interactions and file modifications through a web interface. + +### Key Features + +#### Session Management + +- Creates unique sessions for each batch operation +- Maintains separate logs for API interactions +- Provides tabbed interface for reviewing multiple files + +#### AI Integration + +- Uses configured AI models for code analysis +- Supports interactive refinement of suggestions +- Generates patches in standard diff format + +#### Output Handling + +- Displays results in markdown format +- Provides clickable links for applying changes +- Supports both manual and automatic patch application + +### Technical Details + +#### Configuration Options + +```kotlin +class Settings( + val settings: UserSettings? = null, + val project: Project? = null, +) + +class UserSettings( + var transformationMessage: String = "Review, fix, and improve", + var filesToProcess: List = listOf(), + var autoApply: Boolean = false, +) +``` + +#### Response Format + +The AI generates responses in diff format: + +```diff + +#### path/to/file +```diff + // Context lines +-// Removed lines ++// Added lines + // More context +``` + +``` + + +### Best Practices + +1. **File Selection** + - Review selected files before processing + - Exclude sensitive or generated files + - Process related files together + +2. **Instructions** + - Be specific about desired changes + - Use clear, actionable language + - Consider maintaining a list of proven instructions + +3. **Review Process** + - Always review changes before applying + - Use auto-apply carefully + - Test changes after application + +4. **Performance** + - Process files in manageable batches + - Monitor system resources during large operations + - Consider file size and complexity + +This documentation provides a comprehensive overview of the mass patch functionality, helping users effectively utilize the feature for batch code modifications. + +# generic\ModelSelectionDialog.kt + +Here's the user documentation for the ModelSelectionDialog class: + + +## ModelSelectionDialog + +A dialog component that allows users to select an AI language model from a list of available options. + + +### Overview + +The ModelSelectionDialog presents a simple dropdown interface where users can choose from available ChatGPT/OpenAI models. This dialog is typically used when an action requires user selection of a specific AI model to process requests. + + +### Features + +- Displays a dropdown list of available AI models +- Supports pre-selection of a default model +- Validates that a model is selected before proceeding +- Modal dialog that blocks interaction with the parent window until a selection is made + + +### Usage + +```kotlin +// Create list of available models +val models = listOf(ChatModel(...), ChatModel(...)) + +// Create and show the dialog +val dialog = ModelSelectionDialog( + project = currentProject, + availableModels = models, + initialSelection = defaultModel // Optional +) + +if (dialog.showAndGet()) { + // User clicked OK + val selectedModel = dialog.selectedModel + // Use the selected model... +} else { + // User cancelled the dialog +} +``` + +### Parameters + +- `project`: The current IntelliJ project context (can be null) +- `availableModels`: List of ChatModel objects representing available AI models +- `initialSelection`: (Optional) The default model to pre-select in the dropdown + +### Return Value + +After showing the dialog: + +- Access `selectedModel` property to get the user's selection +- Returns null if no selection was made + +### UI Elements + +- **Model Dropdown**: Lists all available models by name +- **OK Button**: Confirms the selection (disabled if no model is selected) +- **Cancel Button**: Closes dialog without making a selection + +### Validation + +The dialog enforces that a model must be selected before the OK button can be clicked, preventing invalid states. + +# generic\MultiCodeChatAction.kt + +Here's the user documentation for the MultiCodeChatAction: + +## MultiCodeChatAction Documentation + +### Overview + +MultiCodeChatAction is a feature that enables interactive code discussions with an AI assistant across multiple files. It allows developers to select multiple +files or folders and engage in a chat conversation about the code, with support for making code modifications through patches. + +### Features + +- Multi-file code discussion +- Interactive chat interface +- Code modification capabilities +- Support for viewing and applying code patches +- Token count estimation for selected files + +### How to Use + +#### 1. Initiating a Chat Session + +1. Select one or more files/folders in your project explorer +2. Right-click to open the context menu +3. Select the Multi-Code Chat action +4. A browser window will automatically open with the chat interface + +#### 2. Chat Interface + +- The chat interface shows the selected code files at the start of the conversation +- You can type messages and questions about the code in the input field +- The AI assistant will respond with: + - Code explanations + - Suggestions for improvements + - Potential modifications + - Answers to your questions + +#### 3. Code Modifications + +- When the AI suggests code changes, they will appear as patches +- Clickable links will be provided to apply the suggested changes +- You can review the changes before applying them +- Modified files will be updated in your project + +### Requirements + +- Active project in the IDE +- Selected files must exist and be accessible +- Internet connection for AI communication + +### Limitations + +- Files starting with "." (hidden files) are excluded +- Performance may vary based on the size and number of selected files +- Token limits apply based on the selected AI model + +### Tips + +- Select related files for more contextual discussions +- Keep the number of files reasonable to stay within token limits +- Use specific questions to get more targeted responses +- Review suggested changes carefully before applying them + +### Technical Notes + +- Uses the project's root directory as the base path +- Supports multiple file formats +- Changes are tracked and can be managed through your version control system +- API logs are saved for debugging purposes + +For additional support or questions, please refer to the plugin's documentation or contact support. + +# generic\MultiDiffChatAction.kt + +Here's the user documentation for the MultiDiffChatAction class: + +## MultiDiffChatAction Documentation + +### Overview + +MultiDiffChatAction is an IntelliJ IDEA plugin action that enables AI-assisted code modifications across multiple files simultaneously. It provides an +interactive chat interface where users can discuss code changes and apply suggested modifications through diff patches. + +### Features + +- Supports multiple file selection for code review and modifications +- Provides an interactive chat interface with AI assistance +- Generates and applies code patches in diff format +- Maintains context across multiple files +- Supports both file and folder-level operations + +### Usage + +#### Starting the Action + +1. Select one or more files/folders in your IntelliJ project +2. Right-click and select the MultiDiffChat action from the context menu + +- Or use the assigned keyboard shortcut if configured + +#### Chat Interface + +Once initiated, the action will: + +1. Open a web browser window with the chat interface +2. Display the selected files' content +3. Allow you to describe desired changes or ask questions about the code + +#### Working with Patches + +The AI will respond with: + +- Explanatory text about proposed changes +- Code patches in diff format for each affected file +- Links to apply the suggested changes directly to your files + +#### Patch Format Example + +```diff + +#### src/example/File.kt + // Original code context + function example() { +- // Old implementation ++ // New implementation + } +``` + +### Technical Details + +- Supports all text-based file types (excludes binary files) +- Maintains file context with 2 lines before and after changes +- Generates proper diff format with + and - indicators +- Provides file-specific links for applying changes + +### Requirements + +- Active IntelliJ IDEA instance +- Selected files must be text-based (non-binary) +- Valid project configuration with write permissions + +### Limitations + +- Cannot process binary files +- Requires file write permissions +- Changes are applied per-file basis +- Requires network connectivity for AI interaction + +### Best Practices + +1. Review all suggested changes before applying +2. Keep file selections focused and relevant +3. Provide clear, specific instructions for desired changes +4. Test applied changes before committing + +### Error Handling + +- Invalid file selections will be disabled in the UI +- Error messages will be displayed for failed operations +- Network/API errors will be reported in the IDE + +### Support + +For issues or questions: + +- Check the plugin documentation +- Submit issues through the plugin's issue tracker +- Contact plugin support channels + +# generic\MultiStepPatchAction.kt + +Here's the user documentation for the MultiStepPatchAction class: + +## Multi-Step Patch Action + +The Multi-Step Patch Action is an advanced code modification tool that helps automate complex code changes across multiple files in your project. It breaks down +user requests into discrete tasks and implements them systematically. + +### Overview + +This action provides an interactive interface that: + +1. Analyzes your selected files/folders +2. Breaks down your requested changes into specific tasks +3. Generates and applies code patches for each task +4. Provides a web-based interface to review and control the process + +### Usage + +#### Getting Started + +1. Select one or more files/folders in your project that you want to modify +2. Right-click and select "Multi-Step Patch" from the context menu (or use the assigned shortcut) +3. A browser window will open with the Auto Dev Assistant interface + +#### Using the Interface + +1. Enter your desired changes or requirements in natural language in the input field +2. The system will: + +- Analyze your request and break it down into specific tasks +- Show you a task list with detailed descriptions +- Generate code patches for each task +- Provide options to review and apply the changes + +#### Example Workflow + +1. Select your project's source directory +2. Launch Multi-Step Patch +3. Enter a request like: "Add input validation to all public methods" +4. Review the proposed task breakdown +5. Review and approve/modify the generated patches for each task +6. Apply the changes to your codebase + +### Features + +- **Task Breakdown**: Automatically splits complex changes into manageable tasks +- **Multi-File Support**: Can handle changes across multiple files simultaneously +- **Interactive Review**: Provides a web interface to review and control changes +- **Diff Preview**: Shows exact code changes in diff format before applying +- **Context-Aware**: Considers existing code context when generating changes + +### Configuration + +The tool uses the following settings from your IDE's configuration: + +- Smart Model: For complex analysis and task planning +- Fast Model: For parsing and simpler operations +- Plugin Home: For storing session data and logs + +### Best Practices + +1. **Scope Selection**: Select only the relevant files/folders for your change +2. **Clear Instructions**: Provide clear, specific instructions about desired changes +3. **Review Changes**: Always review generated patches before applying them +4. **Incremental Changes**: For large changes, consider breaking them into smaller requests + +### Limitations + +- Requires valid file selection before activation +- Depends on configured AI models for operation +- May require multiple attempts for complex changes +- Network connectivity required for AI operations + +### Troubleshooting + +If you encounter issues: + +1. Check your file selection +2. Verify network connectivity +3. Review logs in the `.logs` directory +4. Ensure AI model settings are configured correctly + +### Technical Details + +- Uses OpenAI API for code analysis and generation +- Implements diff-based code modifications +- Supports multiple programming languages +- Maintains session history for review and rollback + +For additional support or configuration options, refer to the plugin settings in your IDE. + +# generic\OutlineAction.kt + +Here's the user documentation for the OutlineAction class: + +## OutlineAction Documentation + +### Overview + +The OutlineAction class provides functionality to launch an AI-powered outline creation tool within the IDE. It allows users to generate and work with outlines +using AI assistance through a web interface. + +### Features + +- Configurable AI model settings through a dialog +- Web-based interface for outline creation +- Integration with IDE project context +- Asynchronous processing to maintain IDE responsiveness + +### Usage + +1. **Accessing the Action** + +- The outline tool can be accessed through the IDE's action system +- Look for "AI Outline Tool" in menus or use the assigned shortcut + +2. **Configuration** + +- When activated, a configuration dialog will appear +- Settings include: + - Expansion steps with associated AI models + - Temperature setting for AI response variation +- Click OK to proceed or Cancel to abort + +3. **Working with the Tool** + +- After configuration, a web browser window will open +- The interface provides a single input area for outline creation +- Work is automatically saved in the current session +- The session name includes a timestamp for reference + +### Technical Details + +- Runs in background thread to prevent UI freezing +- Creates a unique session ID for each use +- Integrates with the project's AppServer instance +- Uses SkyeNet's OutlineApp framework for AI processing + +### Requirements + +- Active project in IDE +- Valid AI model configuration +- Working internet connection for AI model access + +### Troubleshooting + +If you encounter issues: + +- Check your internet connection +- Verify AI model settings +- Look for error messages in the IDE's log +- Ensure browser launch permissions are granted + +### Notes + +- Session data persists only for the duration of the IDE session +- Browser integration depends on system default browser settings +- Performance may vary based on AI model selection and system resources + +# generic\OutlineConfigDialog.kt + +Here's the user documentation for the OutlineConfigDialog class: + +## Outline Configuration Dialog + +The Outline Configuration Dialog allows users to customize settings for the outline generation tool. This dialog provides controls for configuring the AI models +used in the outline generation process and global temperature settings. + +### Main Components + +#### Outline Generation Steps + +This section displays and manages the sequence of AI models used for generating outlines: + +- A list showing all configured generation steps +- Each step displays the name of the AI model being used +- Controls to add, remove and edit steps: + - **Add Step**: Opens a model selection dialog to add a new generation step + - **Remove Step**: Removes the currently selected step from the sequence + - **Edit Step**: Opens a model selection dialog to modify the selected step's model + +#### Global Temperature + +- A slider control that adjusts the temperature value from 0-100 +- Temperature affects how creative/random the AI responses will be: + - Lower values (closer to 0) produce more focused, deterministic results + - Higher values (closer to 100) produce more varied, creative results + +### Usage + +1. **Adding Steps**: + +- Click "Add Step" +- Select an AI model from the available options +- The new step will be added to the end of the sequence + +2. **Removing Steps**: + +- Select a step from the list +- Click "Remove Step" +- Note: At least one step must remain in the sequence + +3. **Editing Steps**: + +- Select a step from the list +- Click "Edit Step" +- Choose a different model from the dialog + +4. **Adjusting Temperature**: + +- Use the slider to set the desired temperature value +- Changes affect all generation steps + +### Validation + +The dialog enforces the following rules: + +- At least one generation step must be configured +- Only models for which you have valid API keys will be available for selection + +### Default Settings + +If not previously configured, the dialog initializes with: + +- Two identical steps using the default smart model +- Temperature value from global application settings + +Click OK to save changes or Cancel to discard modifications. + +# generic\SessionProxyApp.kt + +Here's the user documentation for the SessionProxyServer class: + +## SessionProxyServer Documentation + +### Overview + +SessionProxyServer is a specialized implementation of ApplicationServer that acts as a proxy for managing AI coding assistant sessions. It provides a web-based +interface for interacting with AI coding tools and manages user sessions and chat functionality. + +### Key Features + +- **Single Input Mode**: Configured to accept one input at a time +- **No Sticky Input**: Input fields are cleared after submission +- **Minimal UI**: Menu bar is hidden by default +- **Session Management**: Handles user sessions and associated chat/agent connections + +### Configuration + +The server is configured with these default settings: + +- Application Name: "AI Coding Assistant" +- Base Path: "/" +- Menu Bar: Hidden +- Image Loading: Disabled +- Single Input Mode: Enabled +- Sticky Input: Disabled + +### Usage + +#### Creating a New Session + +```kotlin +val server = SessionProxyServer() +val session = Session() +val user = User() +val socketManager = server.newSession(user, session) +``` + +#### Managing Sessions + +The server maintains two types of session mappings: + +- `agents`: Maps sessions to SocketManager instances +- `chats`: Maps sessions to ChatServer instances + +### Storage + +The server uses metadata storage configured through ApplicationServices for persisting session data. + +### Error Handling + +- Throws `IllegalStateException` if no agent is found for a session when attempting to create a new session + +### Dependencies + +- Requires SkyeNet WebUI framework +- Uses ApplicationServices for configuration and storage +- Depends on Session and User management components + +### Technical Notes + +- Thread-safe session management using concurrent collections +- Lazy initialization of metadata storage +- Supports both chat-based and agent-based session handling + +This server is primarily used as an internal component of the AI Coding Assistant platform and is not typically interacted with directly by end users. + +# generic\ShellCommandAction.kt + +Here's the user documentation for the ShellCommandAction class: + +## Shell Command Action + +The Shell Command Action provides an interactive interface to execute shell commands in a selected directory through a web-based chat interface. + +### Features + +- Executes shell commands in a specified directory +- Supports both Windows (PowerShell) and Unix-based (Bash) systems +- Provides real-time command output feedback +- Handles command execution errors gracefully +- Integrates with browser-based interface + +### Usage + +1. **Activation**: + +- Select a folder in your project explorer +- Trigger the Shell Command action from the IDE menu or toolbar + +2. **Interface**: + +- A browser window will automatically open with a chat interface +- Enter your shell commands in the input field +- View command output and results in the chat window + +3. **Command Execution**: + +- Commands are executed in the context of the selected directory +- For Windows systems, PowerShell is used as the shell +- For Unix-based systems, Bash is used as the shell + +### Configuration + +The action uses several settings from AppSettingsState: + +- `shellCommand`: The default shell command to execute +- `temperature`: Controls the AI model's response randomness +- `smartModel`: Specifies the AI model to use for command processing + +### Requirements + +- A valid project must be open +- A folder must be selected in the project explorer +- Network access for the browser interface + +### Error Handling + +- Displays error messages if initialization fails +- Provides feedback for command execution errors +- Supports command cancellation + +### Notes + +- The session is uniquely identified and timestamped +- Commands are executed asynchronously to prevent UI freezing +- The interface supports both single commands and command sequences + +This action is particularly useful for developers who need to execute shell commands within their project context while maintaining a clear record of commands +and their outputs. + +# generic\SimpleCommandAction.kt + +Here's the user documentation for the SimpleCommandAction class: + +## SimpleCommandAction Documentation + +### Overview + +SimpleCommandAction is a powerful code assistance tool that allows users to interact with their codebase through natural language commands. It provides an +AI-powered interface for analyzing and modifying code across multiple files. + +### Features + +- Natural language code manipulation +- Multi-file code analysis and modification +- Intelligent file search and context gathering +- Automatic patch generation and application +- Web-based interactive interface + +### Usage + +#### Basic Operation + +1. Select one or more files/folders in your IDE project view +2. Invoke the SimpleCommandAction (via menu or shortcut) +3. A web browser will open with an interactive chat interface +4. Enter your code-related request in natural language +5. The AI will analyze relevant files and propose changes + +#### Example Commands + +``` +"Refactor this code to use dependency injection" +"Add error handling to all database operations" +"Convert these functions to use async/await" +"Add unit tests for this class" +"Optimize the performance of this algorithm" +``` + +#### How It Works + +1. The action analyzes your selected files and project structure +2. It identifies relevant files based on your request +3. The AI processes your request in context of the codebase +4. Proposed changes are presented as diffs in the web interface +5. You can review and apply changes directly from the interface + +### Features in Detail + +#### File Selection + +- Works with single files or multiple files/folders +- Automatically expands folder selections +- Intelligently limits file sizes for optimal performance +- Respects .gitignore rules + +#### Context Awareness + +- Analyzes related files for comprehensive understanding +- Maintains project structure awareness +- Considers file dependencies +- Supports wildcard file patterns + +#### Change Management + +- Presents changes in standard diff format +- Provides file-by-file modification review +- Allows selective application of changes +- Maintains change history within session + +### Limitations + +- Maximum file size limit of 512KB per file +- Total context size limitations based on model constraints +- May require multiple iterations for complex changes +- Browser-based interface required for interaction + +### Best Practices + +1. Be specific in your requests +2. Start with smaller, focused changes +3. Review generated patches carefully +4. Test applied changes thoroughly +5. Use project-specific terminology in requests + +### Technical Notes + +- Runs in background thread for UI responsiveness +- Supports retry mechanisms for reliability +- Includes progress indication for long operations +- Maintains session persistence for ongoing interactions + +### Error Handling + +- Provides clear error messages +- Includes fallback mechanisms +- Supports operation cancellation +- Maintains IDE stability during errors + +### Security + +- Respects project file access permissions +- Operates within IDE security context +- Maintains local code privacy +- Supports configurable API settings + +This documentation provides a comprehensive overview of the SimpleCommandAction functionality. For specific use cases or additional details, please refer to the +inline code comments or contact support. + +# generic\WebDevelopmentAssistantAction.kt + +Here's the user documentation for the WebDevelopmentAssistantAction class: + +## Web Development Assistant + +The Web Development Assistant is an AI-powered tool that helps you create and manage web development projects. It provides an interactive interface to design +and generate web applications with HTML, CSS, JavaScript, and image assets. + +### Features + +- Automated web application architecture design +- Generation of HTML, CSS, and JavaScript files +- Image asset creation +- Code review and refinement +- Interactive development workflow + +### Usage + +1. **Launch the Assistant** + +- Select a directory in your project where you want to create the web application +- Right-click and select "Web Development Assistant" from the context menu +- A browser window will open with the interactive interface + +2. **Describe Your Project** + +- Enter a description of the web application you want to create +- The assistant will analyze your request and create an architecture specification +- You'll see a tabbed view showing both the plain text description and JSON specification + +3. **File Generation** + +- The assistant will automatically generate the necessary files: + - HTML files for structure + - CSS files for styling + - JavaScript files for functionality + - Image assets (PNG/JPG) as needed +- Each file will be created based on the project requirements and best practices + +4. **Code Review and Refinement** + +- After initial file generation, the assistant performs an automated code review +- Suggestions for improvements are presented as code diffs +- You can accept or modify the suggested changes +- The code can be iteratively refined through the interactive interface + +### File Types Supported + +- HTML (.html) +- CSS (.css) +- JavaScript (.js) +- Images (.png, .jpg) +- Other web-related file types + +### Key Components + +- **Architecture Discussion**: Translates your requirements into a detailed project structure +- **Code Generation**: Creates individual files with appropriate code +- **Code Review**: Analyzes the generated code for improvements +- **Image Generation**: Creates image assets using AI +- **Interactive Refinement**: Allows iterative improvement of all generated files + +### Requirements + +- A project directory where files can be created +- Internet connection for AI services +- Proper IDE configuration with required permissions + +### Tips + +- Provide clear, detailed descriptions of your requirements +- Review generated files and suggest refinements as needed +- Use the code review feature to ensure best practices +- Take advantage of the iterative refinement process to perfect your web application + +### Notes + +- Generated files are saved in your selected project directory +- All code is reviewable and modifiable before final implementation +- The assistant maintains proper file organization and structure +- Changes can be undone through your normal version control system + +This tool is designed to streamline web development workflow while maintaining full control over the final implementation. + +# git\ChatWithCommitAction.kt + +Here's the user documentation for the ChatWithCommitAction class: + +## Chat With Commit Action + +The Chat With Commit Action allows you to have an interactive chat discussion about changes made in a commit. This feature helps developers understand and +discuss code changes in a conversational interface. + +### Features + +- Analyzes differences between selected revisions and current working copy +- Handles both text and binary files +- Supports added, deleted, and modified files +- Opens an interactive chat interface to discuss the changes +- Preserves file context and change history + +### Usage + +1. Select one or more files/directories in your project +2. Right-click and select "Chat With Commit" from the context menu +3. The system will: + +- Analyze the selected files for changes +- Generate a diff of the changes +- Open a chat interface in your browser +- Allow you to discuss the changes with an AI assistant + +### Supported Content + +- Text files: Shows detailed line-by-line changes +- Binary files: Indicates binary file changes without content diff +- Added files: Shows full new file content +- Deleted files: Shows removed file content +- Modified files: Shows diff of changes + +### Technical Details + +- Uses diff patch generation to show precise changes +- Integrates with your project's version control system +- Creates a unique session ID for each chat +- Supports multiple chat sessions simultaneously +- Uses configured AI model settings from your IDE preferences + +### Requirements + +- Project must be under version control +- Non-Git version control system (Git repositories are not supported) +- Active internet connection for AI chat functionality +- Browser access for chat interface + +### Notes + +- Chat sessions are preserved with timestamps for future reference +- Changes are displayed in a readable diff format +- Large diffs may take a moment to process +- Binary files are noted but their contents are not compared + +This action is particularly useful for code reviews, understanding historical changes, and discussing code modifications with team members or AI assistance. + +# git\ChatWithCommitDiffAction.kt + +Here's the user documentation for the ChatWithCommitDiffAction: + +## Chat with Commit Diff Action + +### Overview + +The "Chat with Commit Diff" action allows developers to interactively discuss and analyze Git commit differences through a chat interface. This feature helps in +understanding code changes between commits by presenting them in a readable diff format and enabling AI-assisted discussion about those changes. + +### Features + +- Compares selected commit with the current HEAD +- Displays file changes in a diff format +- Opens an interactive chat interface to discuss the changes +- Supports multiple file changes in a single commit +- Shows both additions and deletions in the code + +### How to Use + +1. **Access the Action** + +- Navigate to a commit in your Git history +- Right-click or use the action menu to select "Chat with Commit Diff" + +2. **View Changes** + +- The system will automatically generate a diff between the selected commit and the current state +- Changes are displayed in a standard diff format: + - Lines starting with `+` indicate additions + - Lines starting with `-` indicate deletions + +3. **Chat Interface** + +- A browser window will open with a chat interface +- The diff information will be pre-loaded into the chat context +- You can ask questions or discuss specific aspects of the changes +- The AI will respond based on the context of the changes + +### Requirements + +- Active VCS (Version Control System) in the project +- Valid Git repository +- Selected commit for comparison + +### Error Handling + +- If no VCS is found, an error message will be displayed +- If there are no changes between commits, "No changes found" will be displayed +- Connection issues or other errors will show appropriate error messages + +### Technical Notes + +- Uses the project's configured VCS system +- Integrates with IntelliJ's VCS framework +- Supports standard diff formatting +- Chat sessions are uniquely identified and preserved + +### Limitations + +- Only works with Git repositories +- Requires active internet connection for chat functionality +- Limited to comparing with current HEAD state + +This action is particularly useful for: + +- Code review discussions +- Understanding historical changes +- Documenting the reasoning behind code changes +- Collaborative code analysis + +# git\ChatWithWorkingCopyDiffAction.kt + +Here's the user documentation for the ChatWithWorkingCopyDiffAction: + +## Chat with Working Copy Changes + +The Chat with Working Copy Changes action allows you to have an interactive chat discussion about the uncommitted changes in your Git working directory. + +### Overview + +This feature helps developers: + +- Review and discuss pending changes before committing +- Get AI assistance in understanding code modifications +- Analyze the impact of working copy changes + +### How to Use + +1. Make some changes to files in your Git repository but don't commit them yet +2. Access the action through: + +- Right-click menu in project view +- VCS menu +- Search for "Chat with Working Copy Changes" using Find Action (Ctrl+Shift+A / ⌘⇧A) + +3. The action will: + +- Collect all uncommitted changes in your working directory +- Generate a diff view comparing current state with HEAD +- Open a chat interface in your browser + +4. In the chat interface, you can: + +- Discuss the changes with the AI assistant +- Ask questions about specific modifications +- Get suggestions or feedback on the changes + +### Requirements + +- Project must be under Git version control +- At least one uncommitted change must exist in the working directory +- Valid API configuration in plugin settings + +### Features + +- Shows file-by-file diff information +- Displays both added and removed lines +- Maintains chat history during the session +- Supports markdown formatting in chat +- Browser-based interface for better readability + +### Notes + +- The diff view is read-only - changes must be made in your IDE +- Chat sessions are temporary and not persisted between IDE restarts +- Large diffs may take longer to process +- Internet connection required for AI chat functionality + +### Troubleshooting + +If the action is disabled (grayed out), check that: + +- The project has Git VCS enabled +- You have uncommitted changes in your working directory +- The IDE has proper Git integration configured + +For other issues, check the IDE's log files for error messages. + +# git\ReplicateCommitAction.kt + +Here's the user documentation for the ReplicateCommitAction class: + +## Replicate Commit Action + +The Replicate Commit Action is a powerful feature that allows you to replicate and modify Git commits based on user requirements. This action helps developers +adapt existing code changes to new contexts or requirements. + +### Overview + +This action analyzes selected Git changes and provides an AI-assisted interface to replicate and modify those changes according to specified requirements. It's +particularly useful when you want to: + +- Apply similar changes across different parts of the codebase +- Modify existing commits with new requirements +- Understand and replicate complex code changes + +### How to Use + +1. **Select Changes**: + +- Select one or more files with Git changes in your project +- The changes can be from the current working directory or committed changes + +2. **Launch the Action**: + +- Access via the IDE's action menu or keyboard shortcuts +- The action will only be enabled when valid Git changes are selected + +3. **Interact with the Interface**: + +- A browser window will open showing the selected changes +- Enter your requirements or modifications in the input field +- The AI will analyze the changes and propose modifications + +4. **Review and Apply Changes**: + +- Review the proposed changes in diff format +- Click on the provided links to apply specific changes +- Changes will be applied to your working directory + +### Features + +- **Smart Change Analysis**: Automatically analyzes Git changes and related code context +- **File Filtering**: + - Automatically filters binary files + - Handles file size limits (max 0.5MB per file) + - Respects .gitignore rules + +- **Interactive UI**: + - Shows clear diff previews + - Provides clickable links to apply changes + - Displays both original and modified code + +- **Project Context Awareness**: + - Considers project structure + - Analyzes related files for better context + - Maintains code consistency + +### Limitations + +- File size limit of 0.5MB per file +- Binary files are not processed +- Requires valid Git changes to be selected +- Internet connection required for AI functionality + +### Best Practices + +1. **Select Relevant Changes**: Choose only the changes that are directly related to your replication needs + +2. **Provide Clear Requirements**: Be specific about how you want the changes to be modified + +3. **Review Changes Carefully**: Always review the proposed changes before applying them + +4. **Test After Application**: Test the code after applying changes to ensure functionality + +### Error Handling + +The action includes error handling for common scenarios: + +- Invalid working directory +- Missing Git changes +- File access issues +- Connection problems + +Error messages will be displayed in the IDE's notification system. + +### Technical Requirements + +- Active IntelliJ-based IDE +- Git integration enabled +- Internet connection for AI functionality +- Sufficient file system permissions + +### Support + +For issues or questions: + +- Check the error messages in the IDE's event log +- Ensure your Git integration is working correctly +- Verify file permissions and access rights +- Contact support if problems persist + +This documentation provides a comprehensive overview of the ReplicateCommitAction functionality while remaining accessible to users with varying levels of +technical expertise. + +# knowledge\CreateProjectorFromQueryIndexAction.kt + +Here's the user documentation for the CreateProjectorFromQueryIndexAction: + +## Create Projector from Query Index Action + +This action creates an interactive visualization of document embeddings using TensorFlow Projector from query index data files. + +### Overview + +The Create Projector from Query Index action allows you to visualize document embeddings stored in .index.data files using TensorFlow Projector's interactive 3D +visualization interface. This is useful for exploring relationships between documents and understanding the semantic space of your document collection. + +### Usage + +1. In your IDE, select one or more .index.data files or folders containing .index.data files +2. Right-click and select "Create Projector from Query Index" from the context menu +3. Wait while the action: + +- Reads the document records from the selected files +- Sets up the TensorFlow Projector visualization +- Opens your default web browser to display the interactive visualization + +### Requirements + +- The files must have a .index.data extension +- You must have developer actions enabled in the plugin settings +- The selected files must contain valid document embedding data + +### Features + +- Processes multiple index files at once +- Works with both individual files and folders +- Creates an interactive 3D visualization of document embeddings +- Allows exploration of semantic relationships between documents +- Opens automatically in your default web browser + +### Error Handling + +The action will show error dialogs if: + +- No valid .index.data files are selected +- There are problems reading the data files +- Issues occur during projector creation + +### Notes + +- The visualization may take some time to load depending on the size of your dataset +- The projector interface opens in your default web browser +- The session is preserved and can be accessed later through the session history + +### Technical Details + +- Uses TensorFlow Projector for visualization +- Creates a unique session ID for each projection +- Runs the visualization on a local web server +- Preserves session metadata for future reference + +For more information about TensorFlow Projector and how to interpret the visualizations, please refer to the TensorFlow documentation. + +# knowledge\DocumentDataExtractorAction.kt + +Here's the user documentation for the DocumentDataExtractorAction: + +## Document Data Extractor + +The Document Data Extractor is a powerful tool that uses AI to extract structured data from various document types. It helps you analyze and parse information +from files like PDFs, text documents, HTML files, and markdown files. + +### Features + +- Supports multiple file formats including: + - PDF (.pdf) + - Text files (.txt) + - HTML files (.html, .htm) + - Markdown files (.md) + - Other text-based formats + +- Batch processing capabilities for multiple files and directories +- Configurable parsing settings +- AI-powered data extraction +- Interactive web interface for viewing results + +### Usage + +1. **Select Files** + +- Select one or more files in your project +- You can also select entire directories to process multiple files +- Invalid file types will be automatically filtered out + +2. **Configure Settings** + +- When you run the action, a configuration dialog will appear +- Adjust the parsing settings according to your needs: + - Fast Mode: Toggle for quicker but potentially less detailed processing + - Model Type: Select the appropriate parsing model for your documents + +3. **View Results** + +- After configuration, a web browser will open automatically +- The extracted data will be displayed in a structured format +- Results are saved in the same directory as the source files + +### Requirements + +- Developer actions must be enabled in the plugin settings +- Valid API credentials configured +- Internet connection for AI processing + +### Notes + +- Files ending with `.parsed.json` or `.data` are excluded from processing +- The tool creates a new session for each extraction process +- Results are stored locally and can be accessed later +- Processing time may vary depending on file size and complexity + +### Troubleshooting + +If you encounter any issues: + +- Ensure you have selected valid file types +- Check your internet connection +- Verify API credentials are properly configured +- Look for error messages in the IDE's event log + +For technical support or to report issues, please refer to the plugin's documentation or contact support. + +# knowledge\DocumentDataExtractorConfigDialog.kt + +Here's the user documentation for the DocumentDataExtractorConfigDialog class: + +## DocumentDataExtractorConfigDialog + +A configuration dialog for the Document Data Extractor feature that allows users to customize various settings for parsing and processing documents. + +### Overview + +This dialog provides a user interface to configure multiple settings related to document parsing, including: + +- Parsing model selection +- Image and text processing options +- Output format and file saving preferences +- Performance and display settings + +### Configuration Options + +#### Basic Settings + +- **Parsing Model**: Select the model type to be used for parsing the document +- **DPI**: Set the dots per inch resolution for image processing (must be positive, default: 300) +- **Max Pages**: Maximum number of pages to process (must be positive, default: 100) +- **Output Format**: Specify the desired output format for the processed document +- **Pages Per Batch**: Number of pages to process in each batch (must be positive, default: 10) + +#### File Output Options + +- **Save Image Files**: Enable/disable saving of extracted images +- **Save Text Files**: Enable/disable saving of extracted text +- **Save Final JSON**: Enable/disable saving the final output in JSON format + +#### Display Options + +- **Show Images**: Toggle the display of images during processing +- **Add Line Numbers**: Enable/disable line numbering in the output + +#### Performance Options + +- **Fast Mode**: Enable/disable fast processing mode (may affect quality) + +### Validation + +The dialog performs validation on numeric inputs: + +- DPI must be a positive number +- Max Pages must be a positive integer +- Pages Per Batch must be a positive integer + +Invalid inputs will display error messages and prevent the dialog from being confirmed. + +### Usage + +1. Open the Document Data Extractor configuration dialog +2. Adjust the settings according to your needs +3. Click OK to apply the settings or Cancel to discard changes +4. Invalid settings will be highlighted and must be corrected before proceeding + +Note: All numeric fields must contain valid positive numbers. The dialog will not allow confirmation if any validation errors exist. + +# knowledge\GoogleSearchAndDownloadAction.kt + +Here's the user documentation for the GoogleSearchAndDownloadAction: + +## Google Search and Download Action + +### Overview + +The Google Search and Download Action allows you to perform Google searches and automatically download the search results as HTML files to your project +directory. This feature is particularly useful for research, reference gathering, and content collection tasks. + +### Prerequisites + +To use this action, you need to have: + +1. A valid Google API Key +2. A Google Custom Search Engine ID +3. Developer Actions enabled in the plugin settings + +### Configuration + +Before using the action, ensure you have configured the following in the plugin settings: + +- Google API Key +- Google Custom Search Engine ID + +### Usage + +1. Select a target directory in your project where you want to save the downloaded files +2. Trigger the "Google Search and Download" action +3. In the dialog that appears, enter your search query +4. Click OK to start the search and download process + +### Process + +The action will: + +1. Perform a Google search using your query +2. Download the top 10 search results as HTML files +3. Save the files in your selected directory with names formatted as: `[index]_[sanitized-title].html` + +### Output + +- Downloaded files are saved as HTML documents +- Each file is named using the pattern: `[number]_[page-title].html` +- File names are sanitized to remove invalid characters +- Maximum of 10 results are downloaded + +### Error Handling + +- Failed downloads are logged but won't stop the entire process +- Progress can be monitored in the IDE's progress indicator +- The operation can be cancelled at any time + +### Limitations + +- Maximum of 10 search results per query +- Only HTML content is downloaded +- Requires active internet connection +- Subject to Google API usage limits + +### Troubleshooting + +If the action is not available (grayed out), check that: + +1. You have configured your Google API Key +2. You have configured your Google Search Engine ID +3. Developer Actions are enabled in the plugin settings +4. You have selected a valid target directory + +### Notes + +- Downloaded content is subject to Google's terms of service +- Be mindful of API usage limits and quotas +- Some websites may block automated downloads + +# knowledge\SaveAsQueryIndexAction.kt + +Here's the user documentation for the SaveAsQueryIndexAction: + +## Save As Query Index Action + +### Overview + +The Save As Query Index Action is a utility that converts parsed JSON files into an indexed vector format for efficient querying. This action is particularly +useful for creating searchable knowledge bases from parsed documents. + +### Features + +- Batch processing of multiple JSON files +- Support for processing entire directories +- Multi-threaded processing for improved performance +- Progress tracking with cancellation support + +### Requirements + +- Input files must be in `.parsed.json` format +- Developer actions must be enabled in the application settings +- Valid OpenAI API configuration + +### Usage + +1. **File Selection** + +- Select one or more `.parsed.json` files directly +- Or select directories containing `.parsed.json` files +- Right-click and select "Save As Query Index" from the context menu + +2. **Processing** + +- A progress bar will appear showing the indexing status +- The process can be cancelled at any time using the cancel button +- The system will automatically utilize multiple threads for faster processing + +3. **Completion** + +- A success message will appear when indexing is complete +- The resulting index can be used for vector-based queries + +### Configuration + +The action uses default settings: + +- Thread Count: 8 threads +- Batch Size: 100 items + +### Error Handling + +- Displays error messages for invalid file selections +- Shows progress updates during processing +- Provides feedback for successful completion or cancellation +- Logs errors with detailed messages for troubleshooting + +### Notes + +- This action is only available when developer actions are enabled +- Processing large numbers of files may take significant time +- Ensure sufficient system resources are available for multi-threaded processing + +# legacy\AppendTextWithChatAction.kt + +Here's the user documentation for the AppendTextWithChatAction class: + +## Append Text with AI + +The Append Text action uses AI to intelligently continue and expand your selected text. This feature helps you generate natural continuations of existing +content by leveraging ChatGPT's language capabilities. + +### Usage + +1. Select some text in the editor that you want to continue/expand +2. Right-click and select "Append Text with AI" from the context menu (or use the assigned shortcut if configured) +3. The AI will analyze your selection and generate a natural continuation that flows from the original text + +### Features + +- Seamlessly continues your existing text while maintaining context and style +- Automatically removes any duplicate text if the AI response includes the original selection +- Uses temperature settings from your global configuration to control creativity/randomness +- Leverages the configured "smart model" (typically GPT-4 or similar) for high-quality results + +### Configuration + +This action uses the following settings from your global AI Coder configuration: + +- Smart Model: The AI model used for text generation +- Temperature: Controls randomness/creativity of the generated continuation +- Legacy Actions: Must be enabled for this action to be available + +### Notes + +- The action is part of the legacy feature set and requires "Enable Legacy Actions" to be turned on in settings +- Quality of continuation depends on: + - Length and clarity of selected text + - Context provided in the selection + - Model and temperature settings +- If an error occurs during generation, your original selection will be preserved unchanged + +### Example + +Original selection: + +``` +The quick brown fox +``` + +After append action: + +``` +The quick brown fox jumped over the lazy dog, its russet fur gleaming in the afternoon sun. +``` + +# legacy\CommentsAction.kt + +Here's the user documentation for the CommentsAction class: + +## CommentsAction + +### Overview + +CommentsAction is a legacy action that adds explanatory comments to each line of selected code. It works with various programming languages and helps improve +code readability by automatically generating inline comments. + +### Features + +- Adds explanatory comments to each line of selected code +- Supports multiple programming languages +- Uses AI to generate contextually relevant comments +- Preserves original code structure while adding comments + +### Usage + +1. Select the code you want to comment in the editor +2. Trigger the action via: + +- Menu: Edit > Add Line Comments +- Keyboard shortcut (if configured) +- Right-click context menu + +### Requirements + +- Must be enabled in settings (Legacy Actions must be turned on) +- Requires valid text selection +- File must have a recognized programming language extension + +### Settings + +The following settings affect this action: + +- Legacy Actions must be enabled in the plugin settings +- Temperature setting affects comment variation/creativity +- Model selection affects comment quality +- Human language setting determines comment language + +### Example + +```java +// Before: +int x = 5; +x += 10; +System.out.println(x); + +// After: +int x = 5; // Initialize variable x with value 5 +x += 10; // Add 10 to the value of x +System.out.println(x); // Print the final value of x to console +``` + +### Notes + +- Part of legacy actions suite +- Comments are generated using AI, so results may vary +- Maintains original code formatting +- Works best with clear, well-structured code +- May require manual review of generated comments + +### Troubleshooting + +If the action is not working: + +1. Verify Legacy Actions are enabled in settings +2. Ensure you have valid code selected +3. Check if the file type/language is supported +4. Verify API connectivity and settings + +# legacy\DocAction.kt + +Here's the user documentation for the DocAction class: + +## DocAction - Documentation Generator + +The DocAction class is a code documentation generator that automatically creates documentation comments for selected code blocks in your IDE. + +### Features + +- Generates documentation in the appropriate style for different programming languages (e.g., KDoc for Kotlin, JavaDoc for Java) +- Supports multiple human languages for documentation output +- Intelligently detects code blocks and adjusts selection to cover complete elements +- Uses AI to analyze code and generate meaningful documentation + +### Usage + +1. Select the code block you want to document in your IDE +2. Invoke the "Generate Documentation" action through: + +- The IDE's action menu +- A keyboard shortcut (if configured) +- The context menu + +The action will automatically: + +- Analyze the selected code +- Generate appropriate documentation comments +- Insert the documentation above the selected code block +- Maintain proper indentation + +### Requirements + +- The action only works with programming languages that have defined documentation styles +- The language must be properly recognized by the IDE +- The "Legacy Actions" feature must be enabled in the plugin settings + +### Configuration + +The documentation generation can be customized through the plugin settings: + +- Human language for documentation output +- AI model temperature (controls creativity vs consistency) +- Smart model selection for AI processing + +### Limitations + +- Does not work with plain text files +- Requires a valid documentation style to be defined for the programming language +- May require multiple attempts for complex code blocks + +### Example + +Input: + +```kotlin +fun hello() { + println("Hello, world!") +} +``` + +Output: + +```kotlin +/** + * Prints "Hello, world!" to the console + */ +fun hello() { + println("Hello, world!") +} +``` + +# legacy\ImplementStubAction.kt + +Here's the user documentation for the ImplementStubAction class: + +## Implement Stub Action + +The Implement Stub action helps developers automatically implement stub methods and classes using AI code generation. This feature saves time by generating +meaningful implementations for method/class declarations. + +### Usage + +1. Select a method or class stub/declaration in your code +2. Right-click and select "Implement Stub" from the context menu (or use the assigned shortcut) +3. The AI will analyze the declaration and generate an appropriate implementation + +### Features + +- Automatically detects the programming language of the selected code +- Preserves the original declaration while implementing the body +- Generates implementations that match the context and purpose of the stub +- Works with multiple programming languages (except plain text) +- Respects the project's coding style and patterns + +### Requirements + +- The action must be enabled in settings (Legacy Actions must be enabled) +- The selected code must be in a supported programming language +- A valid method or class declaration must be selected + +### Examples + +```java +// Before +public void processData(String input) { + // TODO: Implement +} + +// After selecting and running "Implement Stub" +public void processData(String input) { + if (input == null || input.isEmpty()) { + throw new IllegalArgumentException("Input cannot be null or empty"); + } + + // Process the input string + String processed = input.trim().toLowerCase(); + + // Perform necessary operations + // ... AI generated implementation ... +} +``` + +### Configuration + +- The implementation style can be influenced by the selected AI model in settings +- The output language can be configured through the human language setting +- Temperature setting affects how creative/conservative the implementations are + +### Limitations + +- Only works with code elements (not plain text) +- Quality of implementation depends on the clarity of the stub/declaration +- May require manual review and adjustments of generated code + +### Troubleshooting + +If you encounter issues: + +- Ensure Legacy Actions are enabled in settings +- Check that you've selected a valid code declaration +- Verify the programming language is supported +- Review error messages for specific issues + +For best results, provide clear and complete declarations with appropriate context. + +# legacy\InsertImplementationAction.kt + +Here's the user documentation for the InsertImplementationAction class: + +## Insert Implementation Action + +### Overview + +The Insert Implementation Action is a code generation feature that automatically implements code based on comments or selected text. It uses AI to generate +appropriate code implementations while considering the context of your codebase. + +### Features + +- Generates code implementations from comments or selected text specifications +- Maintains context awareness of the surrounding code +- Supports multiple programming languages +- Preserves code indentation +- Integrates with project-specific settings + +### Usage + +1. **Select Text or Position Cursor** + +- Place your cursor on a comment describing desired functionality, or +- Select text that describes the implementation you want +- The action will automatically find the nearest relevant comment if no specific selection is made + +2. **Invoke the Action** + +- Use the action shortcut or menu item to trigger the implementation generation +- The action will analyze the context and generate appropriate code + +3. **Review Generated Code** + +- The generated code will be inserted below your selection/comment +- The code maintains proper indentation matching the context + +### Requirements + +- A configured AI model in the plugin settings +- Supported programming language (excludes plain text and Markdown files) +- Legacy actions must be enabled in settings + +### Example + +```java +// Create a function that calculates the factorial of a number +``` + +After invoking the action, it might generate: + +```java +// Create a function that calculates the factorial of a number +public int factorial(int n) { + if (n <= 1) return 1; + return n * factorial(n - 1); +} +``` + +### Troubleshooting + +Common issues and solutions: + +1. **No Code Generated** + +- Ensure AI model is properly configured in settings +- Check if the comment/selection provides clear implementation instructions +- Verify the programming language is supported + +2. **Configuration Errors** + +- Make sure the AI model is selected in plugin settings +- Enable legacy actions if disabled + +3. **Unexpected Results** + +- Try providing more detailed specifications in the comment +- Check if the surrounding code context is properly detected + +### Notes + +- The action works best with clear, specific implementation descriptions +- Generated code considers the context of your existing codebase +- The feature is part of legacy actions and must be explicitly enabled +- Performance may vary based on the complexity of the implementation request + +# legacy\RenameVariablesAction.kt + +Here's the user documentation for the RenameVariablesAction: + +## RenameVariablesAction Documentation + +### Overview + +The RenameVariablesAction is a code refactoring tool that helps improve code readability by suggesting better variable names using AI. It analyzes selected code +and provides intelligent suggestions for renaming variables based on their context and usage. + +### Features + +- AI-powered variable name suggestions +- Support for multiple programming languages +- Interactive selection of which variables to rename +- Batch renaming capability +- Preserves code structure while only modifying variable names + +### How to Use + +1. **Select Code** + +- Highlight the code segment containing variables you want to rename +- The selection can include multiple variables and any surrounding code for context + +2. **Trigger the Action** + +- Access the action through the IDE menu or keyboard shortcut +- The tool will analyze your selected code + +3. **Review Suggestions** + +- A dialog will appear showing suggested renames +- Each suggestion will be displayed as: `originalName -> suggestedName` +- Check the boxes next to the suggestions you want to apply + +4. **Apply Changes** + +- Click OK to apply the selected rename suggestions +- The tool will automatically replace all instances of the selected variables within your selection + +### Requirements + +- The legacy actions feature must be enabled in the plugin settings +- An active internet connection for AI model access +- Sufficient context in the selected code for meaningful suggestions + +### Notes + +- If no suggestions are found, you'll receive a notification +- The tool respects your configured human language preference for generating suggestions +- All changes are applied within the selected text only +- The operation can be cancelled at any time + +### Error Handling + +- If any errors occur during the rename operation, an error dialog will display the details +- Failed operations will not modify your code +- You can retry the operation after addressing any reported issues + +### Best Practices + +- Select enough surrounding code to provide context for better suggestions +- Review suggestions carefully before applying them +- Consider the scope and impact of variable renames in your codebase +- Use this tool as part of a broader code cleanup strategy + +# legacy\ReplaceWithSuggestionsAction.kt + +Here's the user documentation for the ReplaceWithSuggestionsAction class: + +## Replace With Suggestions Action + +The Replace With Suggestions action helps you replace selected text with AI-generated alternatives that fit the surrounding context. + +### Features + +- Analyzes the text before and after your selection to understand the context +- Generates multiple alternative suggestions that could replace the selected text +- Presents suggestions in a radio button dialog for easy selection +- Maintains contextual relevance by considering surrounding text + +### How to Use + +1. Select the text you want to replace in the editor +2. Trigger the "Replace With Suggestions" action +3. Wait while the AI analyzes the context and generates suggestions +4. Choose from the presented alternatives in the radio button dialog +5. The selected suggestion will replace your original text + +### Progress Indicators + +The action shows progress through several stages: + +- "Analyzing context..." - Initial analysis of selected text +- "Preparing context..." - Processing surrounding text for context +- "Generating suggestions..." - AI generation of alternatives + +### Configuration + +- Uses the configured Smart Model from settings +- Temperature setting affects variation in suggestions +- Can be enabled/disabled via "Enable Legacy Actions" setting + +### Notes + +- The action is part of the legacy feature set +- Context window size scales logarithmically with selection length +- Handles errors gracefully with user notifications +- Preserves original text if operation is cancelled + +### Requirements + +- Requires an active project +- Needs text to be selected +- Legacy actions must be enabled in settings + +The action is designed to help you quickly explore alternative phrasings while maintaining contextual relevance to your document. + +# legacy\VoiceToTextAction.kt + +Here's the user documentation for the VoiceToTextAction class: + +## Voice-to-Text Action + +The Voice-to-Text action allows you to dictate text directly into the editor using your microphone. It provides real-time speech-to-text conversion and inserts +the transcribed text at the cursor position or selected text location. + +### Features + +- Real-time audio recording and speech recognition +- Continuous dictation with context awareness +- Visual status indicator +- Works with text selection or cursor position +- Automatic punctuation and formatting + +### Requirements + +- A working microphone connected to your system +- Proper audio system configuration +- Legacy actions enabled in the plugin settings + +### Usage + +1. Position your cursor where you want the dictated text to appear, or select existing text to append to +2. Activate the Voice-to-Text action from the editor context menu or using the assigned shortcut +3. A status window will appear indicating that dictation is active +4. Begin speaking clearly into your microphone +5. The transcribed text will appear in real-time at the cursor position +6. To stop dictation, close the status window + +### Tips + +- Speak clearly and at a moderate pace for best results +- The system maintains context of previous speech (up to 32 words) to improve accuracy +- You can dictate punctuation marks by speaking them (e.g., "period", "comma", etc.) +- The status window can be moved around but should remain visible while dictating + +### Troubleshooting + +If the action is disabled (grayed out), check: + +- That your microphone is properly connected and configured +- Legacy actions are enabled in the plugin settings +- Your system's audio input settings +- The plugin has necessary permissions to access the microphone + +### Technical Notes + +- Uses system audio input at 16kHz sample rate +- Processes audio in chunks with noise filtering +- Maintains a rolling context window for improved transcription accuracy +- Supports both insertion at cursor and appending to selection + +Note: This feature is part of the legacy actions set and may require explicit enablement in the plugin settings. + +# markdown\MarkdownImplementActionGroup.kt + +Here's the user documentation for the MarkdownImplementActionGroup class: + +## Markdown Code Block Implementation Action + +The Markdown Code Block Implementation Action is a feature that allows you to convert natural language descriptions into code blocks in various programming +languages within Markdown files. + +### Overview + +This action appears in the editor when: + +- You are editing a Markdown file +- You have text selected in the editor + +### Supported Languages + +The action supports conversion to the following programming languages: + +- SQL +- Java +- ASP +- C +- Clojure +- CoffeeScript +- C++ +- C# +- CSS +- Bash +- Go +- JavaScript +- LESS +- Make +- MATLAB +- Objective-C +- Pascal +- PHP +- Perl +- Python +- Rust +- SCSS +- SVG +- Swift +- Ruby +- Smalltalk +- VHDL + +### How to Use + +1. Open a Markdown file in the editor +2. Select the text you want to convert to code +3. Right-click to open the context menu +4. Select the target programming language from the available options +5. The selected text will be converted into a code block in the chosen programming language + +### Example + +If you have selected text like: + +``` +Create a function that adds two numbers +``` + +And you choose "Python", it will be converted to: + +````markdown +```python +def add_numbers(a, b): + return a + b +``` +```` + +### Notes + +- The conversion uses AI to interpret your description and generate appropriate code +- The generated code will be wrapped in Markdown code block syntax with the appropriate language identifier +- If an error occurs during conversion, an error dialog will be shown and the original text will be preserved +- The conversion process runs in the background to avoid blocking the UI + +### Configuration + +The action uses the following settings from your IDE configuration: + +- AI model settings from AppSettingsState +- Temperature setting for code generation +- API configuration for the AI service + +### Error Handling + +If the conversion fails: + +- An error dialog will be displayed with details +- The original selected text will be preserved +- The error will be logged for troubleshooting + +# markdown\MarkdownListAction.kt + +Here's the user documentation for the MarkdownListAction: + +## Markdown List Generator + +The Markdown List Generator is a tool that helps you extend existing markdown lists by automatically generating additional list items using AI. + +### Features + +- Works with bullet lists (`-` or `*`) and checkbox lists (`- [ ]`) +- Maintains consistent list formatting and indentation +- Intelligently generates new items based on existing list context +- Supports configurable number of new items to generate + +### Usage + +1. Place your cursor anywhere within an existing markdown list +2. Trigger the action via: + +- Menu: Tools > AI Coder > Markdown > Generate List Items +- Or use the assigned keyboard shortcut + +3. Enter the number of new items you want to generate when prompted +4. The AI will analyze your existing list items and generate new ones in a similar style + +### Examples + +Starting with: + +```markdown +- Item 1 +- Item 2 +- Item 3 +``` + +After generating 3 more items: + +```markdown +- Item 1 +- Item 2 +- Item 3 +- Item 4 +- Item 5 +- Item 6 +``` + +Works with checkbox lists too: + +```markdown +- [ ] Task 1 +- [ ] Task 2 +``` + +### Notes + +- The generator maintains the same list style (bullets, numbers, or checkboxes) as the original list +- Indentation level is preserved for nested lists +- Generated items aim to be contextually relevant to your existing list items +- If an error occurs during generation, an error dialog will be displayed + +### Configuration + +The generation process uses the following settings from your AI Coder configuration: + +- Temperature: Controls the creativity/randomness of generated items +- Model: Uses your configured smart model for generation + +### Requirements + +- Must be used within a markdown file +- Requires an existing list with at least one item +- Requires valid AI Coder configuration and API access + +# plan\AutoPlanChatAction.kt + +Here's the user documentation for the AutoPlanChatAction class: + +## AutoPlanChatAction Documentation + +### Overview + +AutoPlanChatAction is an IntelliJ IDEA plugin action that provides an AI-powered planning and chat interface for software development tasks. It allows users to +interact with an AI assistant that can help plan and execute development tasks while having full context of the project files. + +### Features + +- Interactive chat interface with AI assistant +- Project context awareness +- Code file analysis and summarization +- Configurable AI models and settings +- Shell command execution support (PowerShell/Bash) +- Integration with GitHub and Google APIs + +### Usage + +#### Starting the Chat + +1. Select a file or folder in your project +2. Invoke the Auto Plan Chat action from the IDE +3. Configure settings in the dialog that appears: + +- AI models for chat and parsing +- Temperature setting (0.0-1.0) +- Working directory +- GitHub token (optional) +- Google API credentials (optional) + +#### Configuration Options + +- **Default Model**: Main AI model for chat interactions +- **Parsing Model**: Secondary AI model for code parsing +- **Temperature**: Controls AI response randomness (0.0 = focused, 1.0 = creative) +- **Working Directory**: Project root directory +- **GitHub Token**: For GitHub API integration +- **Google API Key**: For Google search capabilities +- **Google Search Engine ID**: For custom search integration + +#### Limitations + +- Maximum file size limit: 512KB per file +- Performance may vary based on project size +- Requires valid API credentials for full functionality + +#### Tips + +- Select specific files/folders before starting chat for focused context +- For large projects, the system will provide a summary instead of full file contents +- The chat interface opens in your default web browser +- Session information is preserved for future reference + +### Technical Requirements + +- IntelliJ IDEA +- Internet connection for AI model access +- Appropriate API credentials configured +- Compatible operating system (Windows/Linux/Mac) + +### Error Handling + +- Invalid project root errors will be displayed +- API connection issues will show appropriate error messages +- File processing errors are logged and reported +- Browser launch failures are handled gracefully + +This action is part of the AICoder plugin suite and integrates with other development tools and actions within the IDE. + +# plan\PlanAheadAction.kt + +Here's the user documentation for the PlanAheadAction class: + +## PlanAheadAction Documentation + +### Overview + +PlanAheadAction is an IntelliJ IDEA action that provides an AI-powered planning assistant for development tasks. It helps developers break down and plan +implementation work by integrating with language models and development tools. + +### Features + +- Interactive planning dialog to configure settings +- Integration with OpenAI language models +- Support for both Windows (PowerShell) and Unix (Bash) environments +- Project-aware context handling +- Browser-based interface for interaction + +### Usage + +1. Trigger the action from IntelliJ IDEA (via menu or shortcut) +2. Configure planning settings in the dialog: + +- Language models for planning and parsing +- Working directory +- Environment settings +- API keys for GitHub and Google services +- Temperature setting for AI responses + +3. Click OK to launch the planning assistant +4. A browser window will open automatically with the planning interface + +### Configuration Options + +- **Default Model**: Main language model used for planning (configured via app settings) +- **Parsing Model**: Secondary model for parsing tasks (configured via app settings) +- **Working Directory**: Project root or selected folder +- **GitHub Token**: For GitHub API integration +- **Google API Key**: For Google search capabilities +- **Google Search Engine ID**: For custom search integration +- **Temperature**: Controls AI response randomness/creativity + +### Requirements + +- IntelliJ IDEA +- Valid API keys configured in app settings +- Internet connection for API access +- Compatible operating system (Windows/Unix) + +### Technical Notes + +- Runs background tasks on a separate thread (BGT) +- Creates unique session IDs for each planning instance +- Supports both PowerShell and Bash command environments +- Integrates with project file system for context awareness + +### Troubleshooting + +If the browser doesn't open automatically: + +1. Check the IDE log for the URL +2. Wait a few seconds and try again +3. Ensure no firewall is blocking local connections +4. Verify API keys are properly configured + +For any issues, check the IDE logs for detailed error messages. + +# plan\PlanChatAction.kt + +Here's the user documentation for the PlanChatAction class: + +## PlanChatAction Documentation + +### Overview + +PlanChatAction is an IntelliJ IDEA plugin action that provides an interactive chat interface for executing and planning commands in your development +environment. It supports both Windows (PowerShell) and Unix (Bash) environments. + +### Features + +- Interactive command planning and execution interface +- Support for both PowerShell (Windows) and Bash (Unix) shells +- Configurable settings through a dialog +- Integration with project workspace +- Browser-based chat interface + +### Usage + +#### Prerequisites + +- IntelliJ IDEA with the AI Coder plugin installed +- A selected folder or file in the project explorer +- Valid API credentials configured in settings (if using GitHub or Google APIs) + +#### Steps to Use + +1. **Activation**: + +- Select a folder or file in your project +- Trigger the Plan Chat action from the IDE menu or toolbar + +2. **Configuration Dialog**: + A settings dialog will appear where you can configure: + +- Default model for main operations +- Parsing model for command interpretation +- Temperature setting for AI responses +- Working directory +- GitHub token (optional) +- Google API credentials (optional) + +3. **Chat Interface**: + +- After configuration, a browser window will open with the chat interface +- Use the interface to plan and execute commands +- Interact with the AI to get assistance with command execution + +#### Settings + +The action uses several configuration parameters: + +- `defaultModel`: Main AI model for chat interactions +- `parsingModel`: AI model for parsing commands +- `temperature`: Controls AI response randomness +- `workingDir`: Base directory for command execution +- `githubToken`: For GitHub API integration +- `googleApiKey` and `googleSearchEngineId`: For Google API integration + +### Technical Details + +- The action runs in a background thread (BGT) +- Creates a new session for each chat instance +- Automatically detects the operating system for shell selection +- Integrates with the project's module structure +- Uses a web-based interface served locally + +### Troubleshooting + +If you encounter issues: + +1. Check if a folder or file is selected in the project explorer +2. Verify API credentials in settings if using external services +3. Ensure proper project permissions for command execution +4. Check IDE logs for detailed error messages + +### Requirements + +- Active project in IntelliJ IDEA +- Proper file/folder permissions +- Internet connection for AI model access +- Valid API credentials (if using external services) + +# plan\PlanConfigDialog.kt + +Here's the user documentation for the PlanConfigDialog class: + +## Plan Configuration Dialog Documentation + +### Overview + +The Plan Configuration Dialog provides a comprehensive interface for configuring AI-powered task planning and execution settings. It allows users to manage task +configurations, set global parameters, and customize individual task behaviors. + +### Main Features + +#### Configuration Management + +- **Save/Load Configurations**: Save and load named configuration presets +- **Delete Configurations**: Remove saved configuration presets +- **Configuration Naming**: Names must contain only letters, numbers, underscores and hyphens + +#### Global Settings + +- **Auto-fix**: Toggle automatic application of suggested fixes without confirmation +- **Allow Blocking**: Enable/disable UI blocking during task processing +- **Temperature**: Adjust AI response creativity (0-1 scale) + - Lower values: More focused, deterministic responses + - Higher values: More creative, varied responses + +#### Task Configuration + +##### Task List + +- Shows all available task types with visual indicators: + - **Bold**: Enabled tasks + - *Italic*: Disabled tasks +- Hover over tasks to see detailed descriptions + +##### Task Settings + +Each task can be configured with: + +- **Enable/Disable**: Toggle task activation +- **Model Selection**: Choose the AI model to use +- **Command Settings** (for Command Auto-Fix tasks only): + - Enable/disable specific commands + - Add new commands + - Remove existing commands + +#### Available Task Types + +1. **Performance Analysis** + +- Analyzes code performance +- Identifies bottlenecks +- Suggests optimizations + +2. **Web Fetch and Transform** + +- Downloads web content +- Converts to specified formats +- Handles content limitations + +3. **Search Operations** + +- GitHub Search +- Google Search +- Pattern-based Search +- Semantic Search + +4. **Knowledge Management** + +- Content Indexing +- Web Search and Index +- Documentation Generation + +5. **Code Operations** + +- File Modification +- Code Review +- Test Generation +- Optimization +- Security Audit +- Refactoring + +6. **Task Management** + +- Task Planning +- Command Sessions +- Selenium Sessions +- Shell Command Execution + +### Usage Tips + +1. **Configuration Management** + +- Save frequently used configurations for quick access +- Confirm before overwriting existing configurations +- Validate configurations before saving + +2. **Task Selection** + +- Enable only needed tasks to optimize performance +- Ensure models are selected for enabled tasks +- Review task descriptions for optimal usage + +3. **Model Selection** + +- Choose appropriate models based on task requirements +- Verify API key availability for selected models +- Consider model capabilities and limitations + +4. **Performance Optimization** + +- Adjust temperature based on needed creativity level +- Use auto-fix carefully in production environments +- Consider blocking implications in UI-heavy workflows + +### Error Handling + +The dialog provides validation and error checking for: + +- Model selection for enabled tasks +- Configuration name formatting +- Command path validity +- Unsaved changes protection + +### Best Practices + +1. **Configuration Management** + +- Use descriptive names for configurations +- Regular backup of important configurations +- Document configuration purposes + +2. **Task Setup** + +- Start with minimal enabled tasks +- Test configurations in non-production environment +- Monitor task performance and adjust settings + +3. **Model Selection** + +- Match model capabilities to task requirements +- Consider cost implications of model choices +- Maintain backup model options + +4. **Security Considerations** + +- Review command permissions carefully +- Validate web content sources +- Monitor auto-fix behavior + +This dialog is a powerful tool for managing AI-powered development tasks. Take time to understand each setting's impact on your workflow for optimal results. + +# plan\PrePlanAction.kt + +Here's the user documentation for the PrePlanAction class: + +## PrePlanAction Documentation + +### Overview + +PrePlanAction is a UI action that allows users to initiate pre-planned development tasks by providing task breakdown information in JSON format. It integrates +with a planning system to help organize and execute development workflows. + +### Features + +- Accepts task breakdown specifications in JSON format +- Supports template variables with interactive form filling +- Configurable planning settings including models, working directory, and API keys +- Integrates with browser-based task execution interface + +### Usage + +1. **Initiating the Action** + +- Trigger the PrePlanAction from your IDE +- A dialog will appear requesting JSON input for task breakdown + +2. **JSON Input Format** + The input should follow the TaskBreakdownWithPrompt format, which can include: + +- Task descriptions +- Execution steps +- Required resources +- Template variables using `{{variableName}}` syntax + +3. **Template Variables** + +- If your JSON contains template variables (e.g., `{{projectName}}`) +- A form dialog will appear to collect values for each variable +- Enter values for each variable to customize the task breakdown + +4. **Configuration** + After providing the JSON input, you can configure: + +- Default and parsing models +- Command shell (PowerShell for Windows, Bash for others) +- Temperature settings +- Working directory +- Environment variables +- GitHub token +- Google API credentials + +5. **Execution** + +- After configuration, a browser window will open +- The task breakdown will be displayed in a web interface +- You can monitor and control task execution from this interface + +### Requirements + +- Valid JSON input following TaskBreakdownWithPrompt structure +- Appropriate API credentials if using GitHub or Google services +- Project context for working directory +- Internet connection for web interface + +### Error Handling + +- Invalid JSON input will display an error message +- Configuration can be cancelled at any time +- Browser launch failures are logged but non-blocking + +### Notes + +- The action runs in background thread (BGT) to prevent UI freezing +- Session information is preserved for the duration of task execution +- Supports both Windows and Unix-based systems +- Default settings are pulled from application configuration + +# plan\SingleTaskAction.kt + +Here's the user documentation for the SingleTaskAction class: + +## SingleTaskAction Documentation + +### Overview + +SingleTaskAction is an IntelliJ IDEA plugin action that provides a single-task interface for executing AI-assisted tasks in your project. It allows users to +configure and run individual tasks with customized settings and context awareness. + +### Features + +- Interactive configuration dialog for task settings +- Support for both Windows (PowerShell) and Unix (Bash) environments +- Context-aware task execution using selected files +- Integration with OpenAI models +- Browser-based task interface + +### Usage + +#### Basic Steps + +1. Trigger the action from IntelliJ IDEA +2. Configure task settings in the dialog that appears: + +- Select AI models for task execution and parsing +- Set temperature for AI responses (0.0-1.0) +- Configure working directory +- Add optional environment variables +- Set API tokens (GitHub, Google) if needed + +3. Click OK to start the task +4. A browser window will automatically open with the task interface + +#### Context Selection + +- The action can use selected files as context +- Files under 512KB are included in the context +- Context information includes file paths, sizes, and token counts + +#### Configuration Options + +- Default Model: Main AI model for task execution +- Parsing Model: Secondary AI model for parsing +- Temperature: Controls AI response randomness +- Working Directory: Base directory for task execution +- Environment Variables: Custom environment settings +- API Tokens: Optional integration with external services + +### Technical Details + +- Uses Session-based execution +- Supports both PowerShell and Bash command environments +- Integrates with project file system +- Provides async task execution +- Includes progress indication +- Browser-based interface via local server + +### Requirements + +- IntelliJ IDEA +- Valid API credentials (if using external services) +- Internet connection for AI model access + +### Notes + +- Task sessions are uniquely identified +- File context is automatically gathered from selection +- Large files (>512KB) are excluded from context +- Task execution happens asynchronously +- Progress is displayed in IDE + +### Error Handling + +- Initialization failures are reported to the user +- Browser launch failures are logged but non-blocking +- File reading errors are handled gracefully + +This action is part of the AI Coder plugin suite and provides a streamlined interface for single-task AI-assisted development operations. + +# problems\AnalyzeProblemAction.kt + +Here's the user documentation for the AnalyzeProblemAction class: + +## Problem Analysis Action + +The Problem Analysis Action is a powerful tool that helps developers analyze and fix code problems identified in the IDE's problem view. It provides detailed +analysis and suggested fixes for code issues. + +### Features + +- Analyzes problems/errors in your code +- Provides context-aware suggestions for fixes +- Generates code patches in diff format +- Allows direct application of suggested fixes +- Shows related files that may be relevant to the problem + +### How to Use + +1. Open your project in the IDE +2. Navigate to the Problems tool window +3. Select a problem/error you want to analyze +4. Right-click and select "Analyze Problem" from the context menu + +### What Happens + +When you trigger the action: + +1. A new analysis session opens in your browser +2. The tool collects relevant information including: + +- File path and type +- Problem description +- Code context around the error +- Project structure +- Related file contents + +3. The AI analyzes the problem and provides: + +- Detailed error analysis +- List of files that need fixing +- Related files for debugging context +- Specific code patches in diff format + +4. You can review the suggested fixes and: + +- View the changes in diff format +- Apply patches directly to your code +- Navigate to related files +- See the full analysis in a tabbed interface + +### Key Components + +- **Problem Context**: Shows the exact location (line and column) of the error with surrounding code context +- **Project Structure**: Provides relevant project structure information for context +- **File Content**: Shows complete content of affected files +- **Suggested Fixes**: Presents code patches in standard diff format +- **Interactive UI**: Allows direct application of fixes and navigation between files + +### Requirements + +- Active project in the IDE +- Selected problem in the Problems view +- Valid file context + +### Notes + +- The analysis runs in a background thread to prevent UI freezing +- Suggested fixes are presented as diffs that can be applied directly +- All changes can be reviewed before applying +- The tool integrates with your project's Git repository for better context + +This tool is especially useful for: + +- Understanding complex errors +- Getting AI-powered fix suggestions +- Reviewing multiple related files +- Applying fixes efficiently + +# test\TestResultAutofixAction.kt + +Here's the user documentation for the TestResultAutofixAction: + +## Test Result Autofix Action + +The Test Result Autofix Action is an intelligent assistant that helps analyze test failures and suggests fixes automatically. It provides an interactive +interface to review test failures and apply suggested code changes. + +### Features + +- Automatically analyzes test failures and error messages +- Identifies relevant files that need to be fixed +- Suggests specific code changes in diff format +- Provides one-click application of suggested fixes +- Shows file context and project structure + +### When to Use + +Use this action when: + +- A test has failed and you want AI assistance in fixing it +- You need help understanding why a test is failing +- You want to quickly implement fixes for test failures + +### How to Use + +1. **Access the Action** + +- Run your tests in IntelliJ IDEA +- When a test fails, select the failed test in the test runner window +- Right-click and select the "Test Result Autofix" action + +2. **Review Analysis** + +- The action will open a browser window with the analysis +- You'll see: + - Test failure details + - Identified errors + - Affected files + - Suggested fixes in diff format + +3. **Apply Fixes** + +- Review the suggested code changes +- Click the "Apply" links next to each diff to implement the changes +- Changes will be applied to your project files automatically + +### Features in Detail + +#### Test Analysis + +- Shows test name and duration +- Displays complete error messages +- Includes stack traces when available +- Identifies related files that may be relevant + +#### Fix Suggestions + +- Provides context-aware code changes +- Shows changes in standard diff format +- Includes surrounding code context +- Allows selective application of fixes + +#### Project Context + +- Shows relevant project structure +- Lists related files that may need review +- Provides file content for context + +### Tips + +- Review all suggested fixes carefully before applying them +- Check related files mentioned in the analysis +- Consider the broader context of the test failure +- Use the file links to quickly navigate to relevant code + +### Technical Notes + +- The action works with IntelliJ's test framework +- Supports all test types that integrate with IntelliJ +- Changes are applied through IntelliJ's file system +- Uses AI to analyze and suggest fixes + +### Limitations + +- May not catch all possible fix scenarios +- Suggestions should be reviewed before applying +- Large files (>0.5MB) are excluded from analysis +- Requires an active internet connection + +This documentation provides a comprehensive overview of the TestResultAutofixAction functionality and how to use it effectively in your development workflow. \ No newline at end of file diff --git a/docs/tooltips.md b/docs/tooltips.md index b73d5aad..b3dbeaa7 100644 --- a/docs/tooltips.md +++ b/docs/tooltips.md @@ -673,9 +673,10 @@ steps: 2. Fill in any template variables in the JSON input through a dynamic form. 3. Configure advanced planning settings, including AI models, execution environment, and parameters. 4. Launch a web-based interface for the PlanAheadApp, which provides an interactive environment to: - - Review and refine the task breakdown - - Generate and execute steps to complete the task - - Monitor progress and results + +- Review and refine the task breakdown +- Generate and execute steps to complete the task +- Monitor progress and results This action is ideal for complex, multi-step tasks that benefit from AI-assisted planning and execution. It integrates with your project's file system and can execute commands in your development environment. @@ -1272,13 +1273,16 @@ the following steps: 2. Analyzes the project structure and relevant file contents. 3. Uses AI to identify distinct errors and determine which files need to be fixed or are related to the problem. 4. For each identified error, it: - - Examines the content of relevant files - - Generates suggested fixes using AI - - Presents the fixes as code patches in diff format + +- Examines the content of relevant files +- Generates suggested fixes using AI +- Presents the fixes as code patches in diff format + 5. Opens a new browser window with an interactive session where you can: - - View the analysis results - - See suggested fixes for each error - - Apply patches directly to your code + +- View the analysis results +- See suggested fixes for each error +- Apply patches directly to your code This tool is particularly useful for complex issues or when you're unsure how to approach a problem. It leverages AI to provide context-aware solutions tailored to your specific codebase." diff --git a/gradle.properties b/gradle.properties index 84d9ea3f..d25b3c0e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ pluginName=intellij-aicoder pluginRepositoryUrl=https://github.com/SimiaCryptus/intellij-aicoder -pluginVersion=1.8.5 +pluginVersion=1.9.8.3 jvmArgs=-Xmx8g org.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=1g # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html diff --git a/package.json b/package.json deleted file mode 100644 index 4ae011ad..00000000 --- a/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "your-project-name", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "node index.js", - "deploy-forum": "your-deployment-command --env=production" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0", - "npm": ">=9.0.0" - } - "dependencies": { - - } - } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index e37f60f2..865607f3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,17 +1,17 @@ rootProject.name = "intellij-aicoder" -//includeBuild("../jo-penai/") -//includeBuild("../SkyeNet/") +includeBuild("../jo-penai/") +includeBuild("../SkyeNet/") pluginManagement { - repositories { - gradlePluginPortal() - mavenCentral() - } - plugins { - kotlin("jvm") version "2.0.20" apply false - } + repositories { + gradlePluginPortal() + mavenCentral() + } + plugins { + kotlin("jvm") version "2.0.20" apply false + } } plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version ("0.4.0") -} + id("org.gradle.toolchains.foojay-resolver-convention") version ("0.4.0") +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/BaseAction.kt b/src/main/kotlin/aicoder/actions/BaseAction.kt new file mode 100644 index 00000000..9df37947 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/BaseAction.kt @@ -0,0 +1,78 @@ +package aicoder.actions + +/** + * Base action class providing common functionality for AI Coder actions. + * Handles API client initialization and common UI operations. + */ +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.simiacryptus.aicoder.util.IdeaChatClient +import com.simiacryptus.aicoder.util.IdeaOpenAIClient +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.ChatClient +import org.slf4j.LoggerFactory +import javax.swing.Icon + +abstract class BaseAction( + name: String? = null, + description: String? = null, + icon: Icon? = null, +) : AnAction(name, description, icon) { + + private val log by lazy { LoggerFactory.getLogger(javaClass) } + //override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT + /** + * Primary API client for chat interactions + */ + + val api: ChatClient + @JvmName("getChatClient") get() = IdeaChatClient.instance + val api2 = IdeaOpenAIClient.instance + + final override fun update(event: AnActionEvent) { + event.presentation.isEnabledAndVisible = isEnabled(event) + super.update(event) + } + + /** + * Handle the action event + * @param e The action event to handle + */ + + abstract fun handle(e: AnActionEvent) + + /** Determines if this action is enabled in the current context */ + + + final override fun actionPerformed(e: AnActionEvent) { + UITools.logAction( + "Action: ${javaClass.simpleName}".trim() + ) + IdeaChatClient.lastEvent = e + try { + handle(e) + } catch (e: IllegalStateException) { + UITools.error(log, "Invalid state in Action ${javaClass.simpleName}", e) + } catch (e: IllegalArgumentException) { + UITools.error(log, "Invalid input in Action ${javaClass.simpleName}", e) + } catch (e: Throwable) { + UITools.error(log, "Unexpected error in Action ${javaClass.simpleName}", e) + } + } + + open fun isEnabled(event: AnActionEvent): Boolean = true + + + companion object { + val log by lazy { LoggerFactory.getLogger(javaClass) } + val scheduledPool = java.util.concurrent.Executors.newScheduledThreadPool(1).apply { + ApplicationManager.getApplication().executeOnPooledThread { + Runtime.getRuntime().addShutdownHook(Thread { + this.shutdown() + this.awaitTermination(5, java.util.concurrent.TimeUnit.SECONDS) + }) + } + } + } +} diff --git a/src/main/kotlin/aicoder/actions/FileContextAction.kt b/src/main/kotlin/aicoder/actions/FileContextAction.kt new file mode 100644 index 00000000..c626c3ba --- /dev/null +++ b/src/main/kotlin/aicoder/actions/FileContextAction.kt @@ -0,0 +1,137 @@ +package aicoder.actions + +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.UITools +import org.slf4j.LoggerFactory +import java.io.File +import java.nio.file.Path +import java.util.concurrent.TimeUnit + +abstract class FileContextAction( + private val supportsFiles: Boolean = true, + private val supportsFolders: Boolean = true, +) : BaseAction() { + + data class SelectionState( + val selectedFile: File, + val projectRoot: File, + ) + + abstract fun processSelection(state: SelectionState, config: T?, progress: ProgressIndicator): Array + + final override fun handle(e: AnActionEvent) { + val config = getConfig(e.project, e) + if (config == null) { + log.warn("No configuration found for ${javaClass.simpleName}") + return + } + val virtualFile = UITools.getSelectedFile(e) ?: UITools.getSelectedFolder(e) ?: run { + log.warn("No file or folder selected") + return + } + val project = e.project ?: return + val projectBasePath = project.basePath ?: run { + log.error("Project base path is null") + return + } + val projectRoot = File(projectBasePath).toPath() + Thread { + try { + UITools.redoableTask(e) { + UITools.run(e.project, templateText!!, true) { progress -> + val newFiles = try { + processSelection( + SelectionState( + selectedFile = virtualFile.toNioPath().toFile(), + projectRoot = projectRoot.toFile(), + ), config, progress + ) + } catch (ex: Exception) { + log.error("Error processing selection", ex) + throw ex + } finally { + if (progress.isCanceled) throw InterruptedException() + } + val start = System.currentTimeMillis() + val fileSystem = LocalFileSystem.getInstance() + val firstFile = newFiles.firstOrNull() ?: throw IllegalStateException("No files were generated") + var refreshedFile: VirtualFile? = null + while (refreshedFile == null) { + if (System.currentTimeMillis() - start > 10000) { + throw IllegalStateException("Timeout waiting for file to appear: ${firstFile.absolutePath}") + } + refreshedFile = fileSystem.refreshAndFindFileByIoFile(firstFile) + Thread.sleep(500) + } + UITools.writeableFn(e) { + val files = newFiles.mapNotNull { file -> + val generatedFile = fileSystem.refreshAndFindFileByIoFile(file) + if (generatedFile == null) { + log.warn("Generated file not found: ${file.path}") + } else { + open(project, file.toPath()) + } + generatedFile + }.toTypedArray() + Runnable { + files.forEach { it?.delete(this@FileContextAction) } + } + } + } + } + } catch (e: Throwable) { + UITools.error(log, "Error in ${javaClass.simpleName}", e) + } + }.start() + } + + open fun getConfig(project: Project?, e: AnActionEvent): T? = null + + var isDevAction = false + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + if (isDevAction && !AppSettingsState.instance.devActions) return false + val virtualFile = UITools.getSelectedFile(event) ?: UITools.getSelectedFolder(event) ?: return false + return if (virtualFile.isDirectory) supportsFolders else supportsFiles + } + + companion object { + private val log = LoggerFactory.getLogger(FileContextAction::class.java) + + fun open(project: Project, outputPath: Path) { + log.info("Opening file: $outputPath") + lateinit var function: () -> Unit + function = { + val file = outputPath.toFile() + if (file.exists()) { + // Ensure the IDE is ready for file operations + ApplicationManager.getApplication().invokeLater { + val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) + if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { + val localFileSystem = LocalFileSystem.getInstance() + // Refresh the file system to ensure the file is visible + val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) + virtualFile?.let { + FileEditorManager.getInstance(project).openFile(it, true) + } ?: scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } else { + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + } else { + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/LargeOutputChatSocketManager.kt b/src/main/kotlin/aicoder/actions/LargeOutputChatSocketManager.kt new file mode 100644 index 00000000..8a0b4833 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/LargeOutputChatSocketManager.kt @@ -0,0 +1,32 @@ +package aicoder.actions + +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.models.ApiModel +import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.skyenet.core.actors.LargeOutputActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.StorageInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.chat.ChatSocketManager + +class LargeOutputChatSocketManager( + session: Session, + model: ChatModel, + userInterfacePrompt: String, + systemPrompt: String, + api: ChatClient, + storage: StorageInterface?, + applicationClass: Class, + private val largeOutputActor: LargeOutputActor +) : ChatSocketManager( + session = session, + model = model, + userInterfacePrompt = userInterfacePrompt, + systemPrompt = systemPrompt, + api = api, + storage = storage, + applicationClass = applicationClass +) { + override fun respond(api: ChatClient, messages: List) = + largeOutputActor.respond(messages.flatMap { it.content?.mapNotNull { it.text } ?: emptyList() }.toList(), api = api) +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/ModelSelectionDialog.kt b/src/main/kotlin/aicoder/actions/ModelSelectionDialog.kt new file mode 100644 index 00000000..817414fc --- /dev/null +++ b/src/main/kotlin/aicoder/actions/ModelSelectionDialog.kt @@ -0,0 +1,36 @@ +package aicoder.actions + +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.ui.dsl.builder.bindItem +import com.intellij.ui.dsl.builder.panel +import com.simiacryptus.jopenai.models.ChatModel +import javax.swing.JComponent + +class ModelSelectionDialog( + project: Project?, + private val availableModels: List, + private val initialSelection: ChatModel? = null +) : DialogWrapper(project, true) { + + var selectedModel: ChatModel? = null + + init { + init() + title = "Select Model" + } + + override fun createCenterPanel(): JComponent = panel { + row("Model:") { + comboBox(availableModels.map { it.modelName }) + .bindItem({ initialSelection?.modelName }, { selectedItem -> + selectedModel = availableModels.find { it.modelName == selectedItem } + }) + .focused() + .validationOnApply { + if (it.selectedItem == null) error("Please select a model") + null + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/SelectionAction.kt b/src/main/kotlin/aicoder/actions/SelectionAction.kt new file mode 100644 index 00000000..9e89ae20 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/SelectionAction.kt @@ -0,0 +1,198 @@ +package aicoder.actions + +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.RangeMarker +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.NlsSafe +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiRecursiveElementVisitor +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.aicoder.util.LanguageUtils +import com.simiacryptus.aicoder.util.UITools + +abstract class SelectionAction( + private val requiresSelection: Boolean = true +) : BaseAction() { + + open fun getConfig(project: Project?): T? = null + + private fun retarget( + editorState: EditorState, + selectedText: @NlsSafe String?, + selectionStart: Int, + selectionEnd: Int + ): Pair? { + if (selectedText.isNullOrEmpty()) { + var (start, end) = defaultSelection(editorState, selectionStart) + if (start >= end && requiresSelection) return null + start = start.coerceAtLeast(0) + end = end.coerceAtLeast(start).coerceAtMost(editorState.text.length - 1) + return Pair(start, end) + } else { + var (start, end) = editSelection(editorState, selectionStart, selectionEnd) + if (start >= end && requiresSelection) return null + start = start.coerceAtLeast(0) + end = end.coerceAtLeast(start).coerceAtMost(editorState.text.length - 1) + return Pair(start, end) + } + } + + final override fun handle(e: AnActionEvent) { + val editor = e.getData(CommonDataKeys.EDITOR) ?: return + val config = getConfig(e.project) + val indent = UITools.getIndent(e) + val caretModel = editor.caretModel + val primaryCaret = caretModel.primaryCaret + var selectionStart = primaryCaret.selectionStart + var selectionEnd = primaryCaret.selectionEnd + var selectedText = primaryCaret.selectedText + val editorState = editorState(editor) + val (start, end) = retarget(editorState, selectedText, selectionStart, selectionEnd) ?: return + val text = editorState.text + selectedText = text.substring(start.coerceIn(0, (text.length - 1).coerceAtLeast(0)), end.coerceIn(0, (text.length - 1).coerceAtLeast(0))) + selectionEnd = end.coerceIn(0, (text.length - 1).coerceAtLeast(0)) + selectionStart = start.coerceIn(0, (text.length - 1).coerceAtLeast(0)) + + UITools.redoableTask(e) { + val document = e.getData(CommonDataKeys.EDITOR)?.document + var rangeMarker: RangeMarker? = null + WriteCommandAction.runWriteCommandAction(e.project) { + rangeMarker = document?.createGuardedBlock(selectionStart, selectionEnd) + } + val newText = try { + processSelection( + event = e, + SelectionState( + selectedText = selectedText, + selectionOffset = selectionStart, + selectionLength = selectionEnd - selectionStart, + entireDocument = editor.document.text, + language = LanguageUtils.getComputerLanguage(e), + indent = indent, + contextRanges = editorState.contextRanges, + psiFile = editorState.psiFile, + project = e.project, + editor = editor, + ), + config = config + ) + } finally { + if (null != rangeMarker) + WriteCommandAction.runWriteCommandAction(e.project) { + document?.removeGuardedBlock(rangeMarker!!) + } + } + UITools.writeableFn(e) { + UITools.replaceString(editor.document, selectionStart, selectionEnd, newText) + } + } + } + + data class EditorState( + val text: @NlsSafe String, + val cursorOffset: Int, + val line: Pair, + val psiFile: PsiFile?, + val contextRanges: Array = arrayOf(), + ) + + data class ContextRange( + val name: String, + val start: Int, + val end: Int + ) { + fun length() = end - start + fun range() = Pair(start, end) + + fun subString(text: String) = text.substring(start, end) + } + + private fun editorState(editor: Editor): EditorState { + val document = editor.document + val lineNumber = document.getLineNumber(editor.caretModel.offset) + val virtualFile = FileDocumentManager.getInstance().getFile(editor.document) + val psiFile = if (virtualFile == null) { + null + } else { + PsiManager.getInstance(editor.project!!).findFile(virtualFile) + } + return EditorState( + text = document.text, + cursorOffset = editor.caretModel.offset, + line = Pair(document.getLineStartOffset(lineNumber), document.getLineEndOffset(lineNumber)), + psiFile = psiFile, + contextRanges = contextRanges(psiFile, editor) + ) + } + + private fun contextRanges( + psiFile: PsiFile?, + editor: Editor + ): Array { + val contextRanges = mutableListOf() + psiFile?.acceptChildren(object : PsiRecursiveElementVisitor() { + override fun visitElement(element: PsiElement) { + val start = element.textRange.startOffset + val end = element.textRange.endOffset + if (start <= editor.caretModel.offset && end >= editor.caretModel.offset) { + contextRanges.add(ContextRange(element.javaClass.simpleName, start, end)) + } + super.visitElement(element) + } + }) + return contextRanges.toTypedArray() + } + + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val editor = event.getData(CommonDataKeys.EDITOR) ?: return false + if (requiresSelection && editor.caretModel.primaryCaret.selectedText.isNullOrEmpty()) return false + return isLanguageSupported(LanguageUtils.getComputerLanguage(event)) + } + + data class SelectionState( + val selectedText: String? = null, + val selectionOffset: Int = 0, + val selectionLength: Int? = null, + val entireDocument: String? = null, + val language: ComputerLanguage? = null, + val indent: CharSequence? = null, + val contextRanges: Array = arrayOf(), + val psiFile: PsiFile? = null, + val project: Project? = null, + val progress: ProgressIndicator? = null, + val editor: Editor? = null, + ) + + open fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { + return true // LanguageUtils.isLanguageSupported(computerLanguage) + } + + open fun defaultSelection(editorState: EditorState, offset: Int) = editorState.line + + open fun editSelection(state: EditorState, start: Int, end: Int) = Pair(start, end) + + + open fun processSelection( + event: AnActionEvent?, + selectionState: SelectionState, + config: T? + ): String { + return UITools.run(event?.project, templateText ?: "", true) { progress -> + processSelection(state = selectionState, config = config, progress = progress) + } + } + + open fun processSelection(state: SelectionState, config: T?, progress: ProgressIndicator): String { + throw NotImplementedError() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/SessionProxyApp.kt b/src/main/kotlin/aicoder/actions/SessionProxyApp.kt new file mode 100644 index 00000000..fccd36d9 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/SessionProxyApp.kt @@ -0,0 +1,39 @@ +package aicoder.actions + +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.ApplicationServicesConfig.dataStorageRoot +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.chat.ChatServer +import com.simiacryptus.skyenet.webui.session.SocketManager + +class SessionProxyServer : ApplicationServer( + applicationName = "AI Coding Assistant", + path = "/", + showMenubar = false, +) { + override val singleInput = true + override val stickyInput = false + override fun appInfo(session: Session) = appInfoMap.getOrPut(session) { + AppInfoData( + applicationName = applicationName, + singleInput = singleInput, + stickyInput = stickyInput, + loadImages = false, + showMenubar = showMenubar + ) + }.toMap() + + override fun newSession(user: User?, session: Session) = + chats[session]?.newSession(user, session) ?: agents[session] + ?: throw IllegalStateException("No agent found for session $session") + + companion object { + private val log = org.slf4j.LoggerFactory.getLogger(SessionProxyServer::class.java) + val metadataStorage by lazy { ApplicationServices.metadataStorageFactory(dataStorageRoot) } + val agents = mutableMapOf() + val chats = mutableMapOf() + } +} diff --git a/src/main/kotlin/aicoder/actions/agent/CommandAutofixAction.kt b/src/main/kotlin/aicoder/actions/agent/CommandAutofixAction.kt new file mode 100644 index 00000000..164a0d7b --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/CommandAutofixAction.kt @@ -0,0 +1,266 @@ +package aicoder.actions.agent + +/** + * Action that provides automated fixing of command execution issues through AI assistance + */ + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.ComboBox +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.apps.general.CmdPatchApp +import com.simiacryptus.skyenet.apps.general.PatchApp +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import java.awt.BorderLayout +import java.io.File +import java.nio.file.Files +import java.text.SimpleDateFormat +import javax.swing.* +import kotlin.collections.set + +class CommandAutofixAction : BaseAction() { + /** + /** + * Sets up and launches the patch app session with the given settings and files + */ + * Returns the thread that should be used for action update. + */ + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + /** + * Handles the action execution. + * Shows settings dialog, creates patch app session and opens browser interface. + */ + + override fun handle(event: AnActionEvent) { + try { + UITools.runAsync(event.project, "Initializing Command Autofix", true) { progress -> + progress.isIndeterminate = true + progress.text = "Getting settings..." + val settings = getUserSettings(event) ?: return@runAsync + val dataContext = event.dataContext + val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) + setupAndLaunchSession(event, settings, virtualFiles) + } + } catch (e: Throwable) { + log.error("Failed to execute command autofix", e) + UITools.showErrorDialog("Failed to execute command autofix: ${e.message}", "Error") + } + } + + /** + * Sets up and launches the patch app session + */ + private fun setupAndLaunchSession(event: AnActionEvent, settings: PatchApp.Settings, virtualFiles: Array?) { + val folder = UITools.getSelectedFolder(event) + val root = if (null != folder) { + folder.toFile.toPath() + } else { + event.project?.basePath?.let { File(it).toPath() } + }!! + // Validate input parameters + require(settings.executable.exists()) { "Executable file does not exist: ${settings.executable}" } + val patchApp = CmdPatchApp( + root, + settings, + api, + virtualFiles?.map { it.toFile }?.toTypedArray(), + AppSettingsState.instance.smartModel.chatModel() + ) + val session = Session.newGlobalID() + SessionProxyServer.chats[session] = patchApp + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + val dateFormat = SimpleDateFormat("HH:mm:ss") + val sessionName = "${javaClass.simpleName} @ ${dateFormat.format(System.currentTimeMillis())}" + SessionProxyServer.metadataStorage.setSessionName(null, session, sessionName) + val server = AppServer.getServer(event.project) + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + /** + * Checks if the action should be enabled + */ + override fun isEnabled(event: AnActionEvent): Boolean { + if (event.project == null) return false + val folder = UITools.getSelectedFolder(event) + val hasBasePath = event.project?.basePath != null + return folder != null || hasBasePath + } + + companion object { + private val log = LoggerFactory.getLogger(CommandAutofixAction::class.java) + private const val DEFAULT_ARGUMENT = "run build" + private const val MAX_RECENT_ARGUMENTS = 10 + private const val TEXT_AREA_ROWS = 3 + + private fun getUserSettings(event: AnActionEvent?): PatchApp.Settings? { + val root = UITools.getSelectedFolder(event ?: return null)?.toNioPath() ?: event.project?.basePath?.let { + File(it).toPath() + } + val files = UITools.getSelectedFiles(event).map { it.path.let { File(it).toPath() } }.toMutableSet() + if (files.isEmpty()) Files.walk(root) + .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } + .toList().filterNotNull().forEach { files.add(it) } + var settings: PatchApp.Settings? = null + SwingUtilities.invokeAndWait { + val settingsUI = SettingsUI(root!!.toFile()) + val dialog = CommandSettingsDialog(event.project, settingsUI) + dialog.show() + settings = if (dialog.isOK) { + val executable = File(settingsUI.commandField.selectedItem?.toString() ?: throw IllegalArgumentException("No executable selected")) + AppSettingsState.instance.executables += executable.absolutePath + val argument = settingsUI.argumentsField.selectedItem?.toString() ?: "" + AppSettingsState.instance.recentArguments.remove(argument) + AppSettingsState.instance.recentArguments.add(0, argument) + AppSettingsState.instance.recentArguments = + AppSettingsState.instance.recentArguments.take(MAX_RECENT_ARGUMENTS).toMutableList() + PatchApp.Settings( + executable = executable, + arguments = argument, + workingDirectory = File(settingsUI.workingDirectoryField.text), + exitCodeOption = if (settingsUI.exitCodeZero.isSelected) "0" else if (settingsUI.exitCodeAny.isSelected) "any" else "nonzero", + additionalInstructions = settingsUI.additionalInstructionsField.text, + autoFix = settingsUI.autoFixCheckBox.isSelected, + maxRetries = settingsUI.maxRetriesField.value as Int, + ) + } else { + null + } + } + return settings + } + + /** + * UI component class for command settings dialog + */ + + class SettingsUI(root: File) { + val maxRetriesField = JSpinner(SpinnerNumberModel(3, 0, 10, 1)).apply { + toolTipText = "Maximum number of auto-retry attempts (0-10)" + } + val argumentsField = ComboBox().apply { + isEditable = true + AppSettingsState.instance.recentArguments.forEach { addItem(it) } + if (AppSettingsState.instance.recentArguments.isEmpty()) { + addItem(DEFAULT_ARGUMENT) + } + } + val commandField = ComboBox(AppSettingsState.instance.executables.toTypedArray()).apply { + isEditable = true + } + val commandButton = JButton("...").apply { + addActionListener { + val fileChooser = JFileChooser().apply { + fileSelectionMode = JFileChooser.FILES_ONLY + isMultiSelectionEnabled = false + } + if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { + commandField.selectedItem = fileChooser.selectedFile.absolutePath + } + } + } + val workingDirectoryField = JTextField(root.absolutePath).apply { + isEditable = true + } + val workingDirectoryButton = JButton("...").apply { + addActionListener { + val fileChooser = JFileChooser().apply { + fileSelectionMode = JFileChooser.DIRECTORIES_ONLY + isMultiSelectionEnabled = false + this.selectedFile = File(workingDirectoryField.text) + } + if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { + workingDirectoryField.text = fileChooser.selectedFile.absolutePath + } + } + } + val exitCodeOptions = ButtonGroup() + val exitCodeNonZero = JRadioButton("Patch nonzero exit code", true) + val exitCodeZero = JRadioButton("Patch 0 exit code") + val exitCodeAny = JRadioButton("Patch any exit code") + val additionalInstructionsField = JTextArea().apply { + rows = TEXT_AREA_ROWS + lineWrap = true + wrapStyleWord = true + } + val autoFixCheckBox = JCheckBox("Auto-apply fixes").apply { + isSelected = false + } + } + + /** + * Dialog for configuring command autofix settings + */ + + class CommandSettingsDialog(project: Project?, private val settingsUI: SettingsUI) : DialogWrapper(project) { + init { + settingsUI.exitCodeOptions.add(settingsUI.exitCodeNonZero) + settingsUI.exitCodeOptions.add(settingsUI.exitCodeZero) + settingsUI.exitCodeOptions.add(settingsUI.exitCodeAny) + title = "Command Autofix Settings" + init() + } + + override fun createCenterPanel(): JComponent { + val panel = JPanel(BorderLayout()).apply { + + val optionsPanel = JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + add(JLabel("Executable")) + add(JPanel(BorderLayout()).apply { + add(settingsUI.commandField, BorderLayout.CENTER) + add(settingsUI.commandButton, BorderLayout.EAST) + }) + add(JLabel("Arguments")) + add(settingsUI.argumentsField) + add(JLabel("Working Directory")) + add(JPanel(BorderLayout()).apply { + add(settingsUI.workingDirectoryField, BorderLayout.CENTER) + add(settingsUI.workingDirectoryButton, BorderLayout.EAST) + }) + add(JLabel("Exit Code Options")) + add(settingsUI.exitCodeNonZero) + add(settingsUI.exitCodeAny) + add(settingsUI.exitCodeZero) + add(JLabel("Max Auto-Retries")) + add(settingsUI.maxRetriesField) + add(JLabel("Additional Instructions")) + add(JScrollPane(settingsUI.additionalInstructionsField)) + add(settingsUI.autoFixCheckBox) + } + add(optionsPanel, BorderLayout.SOUTH) + } + return panel + } + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/agent/DocumentedMassPatchAction.kt b/src/main/kotlin/aicoder/actions/agent/DocumentedMassPatchAction.kt new file mode 100644 index 00000000..183a1f7f --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/DocumentedMassPatchAction.kt @@ -0,0 +1,194 @@ +package aicoder.actions.agent + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.generate.items +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.ui.CheckBoxList +import com.intellij.ui.components.JBScrollPane +import com.intellij.ui.components.JBTextArea +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.Name +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.util.FileValidationUtils.Companion.isLLMIncludableFile +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import java.awt.BorderLayout +import java.awt.Dimension +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.text.SimpleDateFormat +import javax.swing.* + +class DocumentedMassPatchAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + class SettingsUI { + @Name("Documentation Files") + val documentationFiles = CheckBoxList() + + @Name("Code Files") + val codeFiles = CheckBoxList() + + @Name("AI Instruction") + val transformationMessage = JBTextArea(4, 40) + + @Name("Recent Instructions") + val recentInstructions = JComboBox() + + @Name("Auto Apply") + val autoApply = JCheckBox("Auto Apply Changes") + } + + class UserSettings( + var transformationMessage: String = "Review and update code according to documentation standards", + var documentationFiles: List = listOf(), + var codeFilePaths: List = listOf(), + var autoApply: Boolean = false, + ) + + class Settings( + val settings: UserSettings? = null, + val project: Project? = null, + ) + + override fun handle(e: AnActionEvent) { + val project = e.project + val config = getConfig(project, e) + if (config == null) return + + val session = Session.newGlobalID() + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = DocumentedMassPatchServer( + config = config, + api = api, + autoApply = config.settings?.autoApply ?: false + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Documented Code Patch", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + + val server = AppServer.getServer(e.project) + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + private fun getConfig(project: Project?, e: AnActionEvent): Settings? { + var root = UITools.getSelectedFolder(e)?.toNioPath() + val allFiles: List = root?.let { Files.walk(it).toList() } + ?: UITools.getSelectedFiles(e).map { it.toNioPath() } + if (root == null) { + root = e.project?.basePath?.let { File(it).toPath() } + } + val docFiles: Array = allFiles.filter { it.toString().endsWith(".md") }.toTypedArray() + val sourceFiles: Array = allFiles.filter { + isLLMIncludableFile(it.toFile()) && !it.toString().endsWith(".md") + }.toTypedArray() + + val settingsUI = SettingsUI().apply { + documentationFiles.setItems(docFiles.toMutableList()) { path -> + root?.relativize(path)?.toString() ?: path.toString() + } + codeFiles.setItems(sourceFiles.toMutableList()) { path -> + root?.relativize(path)?.toString() ?: path.toString() + } + + docFiles.forEach { path -> + documentationFiles.setItemSelected(path, true) + } + sourceFiles.forEach { path -> + codeFiles.setItemSelected(path, true) + } + autoApply.isSelected = false + } + + val dialog = ConfigDialog(project, settingsUI, "Documented Mass Patch") + dialog.show() + if (!dialog.isOK) return null + + return Settings(dialog.userSettings, project) + } + + class ConfigDialog(project: Project?, private val settingsUI: SettingsUI, title: String) : DialogWrapper(project) { + val userSettings = UserSettings() + + init { + this.title = title + settingsUI.transformationMessage.text = userSettings.transformationMessage + settingsUI.autoApply.isSelected = userSettings.autoApply + init() + } + + override fun createCenterPanel(): JComponent { + return JPanel(BorderLayout()).apply { + val splitPane = JSplitPane(JSplitPane.VERTICAL_SPLIT).apply { + topComponent = JPanel(BorderLayout()).apply { + add(JLabel("Documentation Files"), BorderLayout.NORTH) + add(JBScrollPane(settingsUI.documentationFiles), BorderLayout.CENTER) + } + bottomComponent = JPanel(BorderLayout()).apply { + add(JLabel("Code Files"), BorderLayout.NORTH) + add(JBScrollPane(settingsUI.codeFiles), BorderLayout.CENTER) + } + preferredSize = Dimension(400, 500) + } + + add(splitPane, BorderLayout.CENTER) + add(JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + add(JLabel("AI Instruction")) + add(settingsUI.transformationMessage) + add(Box.createVerticalStrut(10)) + add(settingsUI.autoApply) + }, BorderLayout.SOUTH) + } + } + + override fun doOKAction() { + super.doOKAction() + userSettings.apply { + transformationMessage = settingsUI.transformationMessage.text + documentationFiles = settingsUI.documentationFiles.items + .filter { settingsUI.documentationFiles.isItemSelected(it) } + codeFilePaths = settingsUI.codeFiles.items + .filter { settingsUI.codeFiles.isItemSelected(it) } + autoApply = settingsUI.autoApply.isSelected + } + } + } + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + UITools.getSelectedFolder(event) ?: UITools.getSelectedFiles(event).let { + when (it.size) { + 0 -> null + 1 -> null + else -> it + } + } ?: return false + return true + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/agent/DocumentedMassPatchServer.kt b/src/main/kotlin/aicoder/actions/agent/DocumentedMassPatchServer.kt new file mode 100644 index 00000000..b836375e --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/DocumentedMassPatchServer.kt @@ -0,0 +1,176 @@ +package aicoder.actions.agent + +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.diff.AddApplyFileDiffLinks + +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.models.ApiModel +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import com.simiacryptus.skyenet.Discussable +import com.simiacryptus.skyenet.TabbedDisplay +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager +import com.simiacryptus.skyenet.webui.session.SocketManager +import java.nio.file.Path +import java.util.* +import java.util.concurrent.Semaphore +import java.util.concurrent.atomic.AtomicReference + +class DocumentedMassPatchServer( + val config: DocumentedMassPatchAction.Settings, + val api: ChatClient, + val autoApply: Boolean + /** + * Server for handling documented mass code patches + * @param config Settings containing project and file configurations + * @param api ChatClient for AI interactions + * @param autoApply Whether to automatically apply suggested patches */ +) : ApplicationServer( + applicationName = "Documented Code Patch", + path = "/patchChat", + showMenubar = false, +) { + private lateinit var _root: Path + + override val singleInput = false + override val stickyInput = true + + /** + * Main actor for processing code reviews and generating patches + */ + + private val mainActor: SimpleActor + get() { + return SimpleActor( + prompt = """ + You are a helpful AI that helps people with coding. + + You will be reviewing code files based on documentation files and suggesting improvements. + Please analyze both the documentation and code to ensure they are aligned and suggest improvements. + + Response should use one or more code patches in diff format within ```diff code blocks. + Each diff should be preceded by a header that identifies the file being modified. + The diff format should use + for line additions, - for line deletions. + The diff should include 2 lines of context before and after every change. + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + ) + } + + /** + * Creates a new session for handling code review and patch generation + * @param user The user initiating the session + * @param session The session context + * @return SocketManager for managing the session + */ + + override fun newSession(user: User?, session: Session): SocketManager { + val socketManager = super.newSession(user, session) + val ui = (socketManager as ApplicationSocketManager).applicationInterface + _root = config.project?.basePath?.let { Path.of(it) } ?: Path.of(".") + val task = ui.newTask(true) + val api = (api as ChatClient).getChildClient().apply { + val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") + // Handle potential null from createFile + createFile.second?.apply { + logStreams += this.outputStream().buffered() + task.add("Initializing API logging...") + task.verbose("API log: $this") + } + } + + val tabs = TabbedDisplay(task) + val userMessage = config.settings?.transformationMessage ?: "Review and update code according to documentation" + + // Process documentation files first + val docSummary = config.settings?.documentationFiles?.joinToString("\n\n") { path -> + """ + # Documentation: $path + ```md + ${_root.resolve(path).toFile().readText(Charsets.UTF_8)} + ``` + """.trimIndent() + } ?: "" + + // Then process code files + config.settings?.codeFilePaths?.forEach { path: Path -> + socketManager.scheduledThreadPoolExecutor.schedule({ + socketManager.pool.submit { + try { + task.add("Processing ${path}...") + val codeSummary = """ + $docSummary + + # Code: $path + ```${path.toString().split('.').lastOrNull()} + ${_root.resolve(path).toFile().readText(Charsets.UTF_8)} + ``` + """.trimIndent() + + val fileTask = ui.newTask(false).apply { + tabs[path.toString()] = placeholder + } + + val toInput = { it: String -> listOf(codeSummary, it) } + Discussable( + task = fileTask, + userMessage = { userMessage }, + heading = renderMarkdown(userMessage), + initialResponse = { + mainActor.answer(toInput(it), api = api) + }, + outputFn = { design: String -> + """
${ + renderMarkdown(design) { + AddApplyFileDiffLinks.instrumentFileDiffs( + self = ui.socketManager!!, + root = _root, + response = design, + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + fileTask.complete("$path Updated") + } + }, + ui = ui, + api = api as API, + shouldAutoApply = { autoApply }, + model = AppSettingsState.instance.fastModel.chatModel(), + defaultFile = path.toString() + ) + } + }
""" + }, + ui = ui, + reviseResponse = { userMessages -> + mainActor.respond( + messages = userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } + .toTypedArray(), + input = toInput(userMessage), + api = api + ) + }, + atomicRef = AtomicReference(), + semaphore = Semaphore(0), + ).call() + task.add("Completed processing ${path}") + } catch (e: Exception) { + log.warn("Error processing $path", e) + task.error(ui, e) + } + } + }, 10, java.util.concurrent.TimeUnit.MILLISECONDS) + } + return socketManager + } + + companion object { + private val log = org.slf4j.LoggerFactory.getLogger(DocumentedMassPatchServer::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/agent/MassPatchAction.kt b/src/main/kotlin/aicoder/actions/agent/MassPatchAction.kt new file mode 100644 index 00000000..4a9a7c4e --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/MassPatchAction.kt @@ -0,0 +1,363 @@ +package aicoder.actions.agent + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.MassPatchAction.Settings +import aicoder.actions.generate.items +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.ui.CheckBoxList +import com.intellij.ui.components.JBScrollPane +import com.intellij.ui.components.JBTextArea +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.config.Name +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.diff.AddApplyFileDiffLinks +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.models.ApiModel +import com.simiacryptus.jopenai.models.ApiModel.Role +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import com.simiacryptus.skyenet.Discussable +import com.simiacryptus.skyenet.TabbedDisplay +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.core.util.FileValidationUtils.Companion.isLLMIncludableFile +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager +import com.simiacryptus.skyenet.webui.session.SocketManager +import java.awt.BorderLayout +import java.awt.Dimension +import java.nio.file.Files +import java.nio.file.Path +import java.text.SimpleDateFormat +import java.util.* +import java.util.concurrent.Semaphore +import java.util.concurrent.atomic.AtomicReference +import javax.swing.* + +class MassPatchAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + private val log = org.slf4j.LoggerFactory.getLogger(MassPatchAction::class.java) + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + UITools.getSelectedFolder(event) ?: UITools.getSelectedFiles(event).let { + when (it.size) { + 0 -> null + 1 -> null + else -> it + } + } ?: return false + return true + } + + class SettingsUI { + @Name("Files to Process") + val filesToProcess = CheckBoxList() + + @Name("AI Instruction") + val transformationMessage = JBTextArea(4, 40) + + @Name("Recent Instructions") + val recentInstructions = JComboBox() + + @Name("Auto Apply") + val autoApply = JCheckBox("Auto Apply Changes") + } + + class UserSettings( + var transformationMessage: String = "Review, fix, and improve", + var filesToProcess: List = listOf(), + var autoApply: Boolean = false, + ) + + class Settings( + val settings: UserSettings? = null, + val project: Project? = null, + ) + + fun getConfig(project: Project?, e: AnActionEvent): Settings? { + val root = UITools.getSelectedFolder(e)?.toNioPath() + val files = Files.walk(root) + .filter { isLLMIncludableFile(it.toFile()) } + .toList().filterNotNull().toTypedArray() + val settingsUI = SettingsUI().apply { + filesToProcess.setItems(files.toMutableList()) { path -> + root?.relativize(path)?.toString() ?: path.toString() + } + files.forEach { path -> + filesToProcess.setItemSelected(path, true) + } + autoApply.isSelected = false + } + val mruPatchInstructions = AppSettingsState.instance.getRecentCommands("PatchInstructions") + settingsUI.recentInstructions.model = DefaultComboBoxModel( + mruPatchInstructions.getMostRecent(10).toTypedArray() + ) + settingsUI.recentInstructions.selectedIndex = -1 + settingsUI.recentInstructions.addActionListener { + updateUIFromSelection(settingsUI) + } + + val dialog = ConfigDialog(project, settingsUI, "Mass Patch") + dialog.show() + if (!dialog.isOK) return null + val settings: UserSettings = dialog.userSettings + settings.filesToProcess = files.filter { path -> settingsUI.filesToProcess.isItemSelected(path) }.toList() + mruPatchInstructions.addInstructionToHistory(settings.transformationMessage) + return Settings(settings, project) + } + + private fun updateUIFromSelection(settingsUI: SettingsUI) { + val selected = settingsUI.recentInstructions.selectedItem as? String + if (selected != null) { + settingsUI.transformationMessage.text = selected + } + } + + + override fun handle(event: AnActionEvent) { + try { + val project = event.project + val config = getConfig(project, event) + if (config == null) { + log.info("Configuration cancelled by user") + return + } + + val session = Session.newGlobalID() + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = MassPatchServer(config = config!!, api = api, autoApply = config.settings?.autoApply ?: false) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + + val server = AppServer.getServer(event.project) + UITools.runAsync(project, "Opening browser") { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + UITools.showErrorDialog("Failed to open browser: ${e.message}", "Error") + } + } + } catch (e: Exception) { + log.error("Error in mass patch action", e) + UITools.showErrorDialog(e.message ?: "", "Error") + } + + } + + class ConfigDialog(project: Project?, private val settingsUI: SettingsUI, title: String) : DialogWrapper(project) { + val userSettings = UserSettings() + + init { + this.title = title +// Set the default values for the UI elements from userSettings + settingsUI.transformationMessage.text = userSettings.transformationMessage + settingsUI.autoApply.isSelected = userSettings.autoApply + init() + } + + override fun createCenterPanel(): JComponent { + val panel = JPanel(BorderLayout()).apply { + val filesScrollPane = JBScrollPane(settingsUI.filesToProcess).apply { + preferredSize = Dimension(400, 300) // Adjust the preferred size as needed + } + add(JLabel("Files to Process"), BorderLayout.NORTH) + add(filesScrollPane, BorderLayout.CENTER) // Make the files list the dominant element + + val optionsPanel = JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + add(JLabel("Recent Instructions")) + add(settingsUI.recentInstructions) + add(Box.createVerticalStrut(10)) + add(JLabel("AI Instruction")) + add(settingsUI.transformationMessage) + add(Box.createVerticalStrut(10)) + add(settingsUI.autoApply) + } + add(optionsPanel, BorderLayout.SOUTH) + } + return panel + } + + override fun doOKAction() { + super.doOKAction() + userSettings.transformationMessage = settingsUI.transformationMessage.text + userSettings.filesToProcess = + settingsUI.filesToProcess.items.filter { path -> settingsUI.filesToProcess.isItemSelected(path) } + userSettings.autoApply = settingsUI.autoApply.isSelected + } + } +} + +class MassPatchServer( + val config: Settings, + val api: ChatClient, + val autoApply: Boolean +) : ApplicationServer( + applicationName = "Multi-file Patch Chat", + path = "/patchChat", + showMenubar = false, +) { + private val log = org.slf4j.LoggerFactory.getLogger(MassPatchServer::class.java) + private lateinit var _root: Path + + + override val singleInput = false + override val stickyInput = true + private val mainActor: SimpleActor + get() { + + return SimpleActor( + prompt = """ + You are a helpful AI that helps people with coding. + + Response should use one or more code patches in diff format within ```diff code blocks. + Each diff should be preceded by a header that identifies the file being modified. + The diff format should use + for line additions, - for line deletions. + The diff should include 2 lines of context before and after every change. + + Example: + + Here are the patches: + + ### src/utils/exampleUtils.js + ```diff + // Utility functions for example feature + const b = 2; + function exampleFunction() { + - return b + 1; + + return b + 2; + } + ``` + + ### tests/exampleUtils.test.js + ```diff + // Unit tests for exampleUtils + const assert = require('assert'); + const { exampleFunction } = require('../src/utils/exampleUtils'); + + describe('exampleFunction', () => { + - it('should return 3', () => { + + it('should return 4', () => { + assert.equal(exampleFunction(), 3); + }); + }); + ``` + + If needed, new files can be created by using code blocks labeled with the filename in the same manner. + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + ) + } + + + override fun newSession(user: User?, session: Session): SocketManager { + val socketManager = super.newSession(user, session) + val ui = (socketManager as ApplicationSocketManager).applicationInterface + try { + _root = config.project?.basePath?.let { Path.of(it) } + ?: throw IllegalStateException("Project base path not found") + } catch (e: Exception) { + log.error("Failed to initialize root path", e) + throw e + } + val task = ui.newTask(true) + val api = (api as ChatClient).getChildClient().apply { + val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") + createFile.second?.apply { + logStreams += this.outputStream().buffered() + task.verbose("API log: $this") + } + } + val tabs = TabbedDisplay(task) + val userMessage = config.settings?.transformationMessage ?: "Create user documentation" + val codeFiles = config.settings?.filesToProcess + codeFiles?.forEach { path -> + socketManager.scheduledThreadPoolExecutor.schedule({ + socketManager.pool.submit { + try { + val codeSummary = listOf(path) + .filter { isLLMIncludableFile(it.toFile()) } + .associateWith { it.toFile().readText(Charsets.UTF_8) } + .entries.joinToString("\n\n") { (path, code) -> + val extension = path.toString().split('.').lastOrNull() + "# $path\n```$extension\n$code\n```" + } + val fileTask = ui.newTask(false).apply { + tabs[path.toString()] = placeholder + } + val toInput = { it: String -> listOf(codeSummary ?: "", it) } + Discussable( + task = fileTask, + userMessage = { userMessage }, + heading = renderMarkdown(userMessage), + initialResponse = { + mainActor.answer(toInput(it), api = api) + }, + outputFn = { design: String -> + val markdown = AddApplyFileDiffLinks.instrumentFileDiffs( + ui.socketManager!!, + root = _root, + response = design, + handle = { newCodeMap: Map -> + newCodeMap.forEach { (path, newCode) -> + fileTask.complete("$path Updated") + } + }, + ui = ui, + api = api as API, + shouldAutoApply = { autoApply }, + model = AppSettingsState.instance.fastModel.chatModel(), + ) + """
${renderMarkdown(markdown)}
""" + }, + ui = ui, + reviseResponse = { userMessages: List> -> + mainActor.respond( + messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } + .toTypedArray()), + input = toInput(userMessage), + api = api + ) + }, + atomicRef = AtomicReference(), + semaphore = Semaphore(0), + ).call() + } catch (e: Exception) { + log.warn("Error processing $path", e) + task.error(ui, e) + } + } + }, 10, java.util.concurrent.TimeUnit.MILLISECONDS) + } + return socketManager + } + + companion object { + val log = org.slf4j.LoggerFactory.getLogger(MassPatchServer::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/agent/MultiStepPatchAction.kt b/src/main/kotlin/aicoder/actions/agent/MultiStepPatchAction.kt new file mode 100644 index 00000000..74860562 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/MultiStepPatchAction.kt @@ -0,0 +1,368 @@ +package aicoder.actions.agent + +import ai.grazie.utils.mpp.UUID +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.application.ApplicationManager +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.diff.AddApplyFileDiffLinks +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.describe.Description +import com.simiacryptus.jopenai.models.ApiModel +import com.simiacryptus.jopenai.models.ApiModel.Role +import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ValidatedObject +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import com.simiacryptus.skyenet.AgentPatterns +import com.simiacryptus.skyenet.Discussable +import com.simiacryptus.skyenet.Retryable +import com.simiacryptus.skyenet.TabbedDisplay +import com.simiacryptus.skyenet.core.actors.ParsedActor +import com.simiacryptus.skyenet.core.actors.ParsedResponse +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.file.DataStorage +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.core.util.commonRoot +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.util.JsonUtil.toJson +import org.slf4j.LoggerFactory +import java.io.File +import java.nio.file.Path +import java.text.SimpleDateFormat +import java.util.concurrent.Semaphore +import java.util.concurrent.atomic.AtomicReference + +class MultiStepPatchAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + val path = "/autodev" + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + UITools.getSelectedFile(event) ?: return false + return true + } + + + override fun handle(e: AnActionEvent) { + val project = e.project ?: return + UITools.runAsync(project, "Initializing Auto Dev Assistant", true) { progress -> + progress.isIndeterminate = true + try { + val session = Session.newGlobalID() + val storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) as DataStorage? + val selectedFile = UITools.getSelectedFolder(e) + if (null != storage && null != selectedFile) { + DataStorage.sessionPaths[session] = selectedFile.toFile + } + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = AutoDevApp(event = e) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + val server = AppServer.getServer(e.project) + + + ApplicationManager.getApplication().invokeLater { + progress.text = "Opening browser..." + val uri = server.server.uri.resolve("/#$session") + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } + } catch (e: Throwable) { + UITools.error(log, "Failed to initialize Auto Dev Assistant", e) + } + } + } + + open class AutoDevApp( + applicationName: String = "Auto Dev Assistant v1.2", + val temperature: Double = 0.1, + val event: AnActionEvent, + ) : ApplicationServer( + applicationName = applicationName, + path = "/autodev", + showMenubar = false, + ) { + companion object { + private const val DEFAULT_BUDGET = 2.00 + } + + override fun userMessage( + session: Session, + user: User?, + userMessage: String, + ui: ApplicationInterface, + api: API + ) { + val settings = getSettings(session, user) ?: Settings( + budget = DEFAULT_BUDGET, + model = AppSettingsState.instance.smartModel.chatModel() + ) + if (api is ChatClient) api.budget = settings.budget ?: DEFAULT_BUDGET + AutoDevAgent( + api = api, + session = session, + user = user, + ui = ui, + model = settings.model!!, + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + event = event, + ).start( + userMessage = userMessage, + ) + } + + data class Settings( + val budget: Double? = 2.00, + val tools: List = emptyList(), + val model: ChatModel? = AppSettingsState.instance.smartModel.chatModel(), + ) + + override val settingsClass: Class<*> get() = Settings::class.java + + @Suppress("UNCHECKED_CAST") + override fun initSettings(session: Session): T? = Settings() as T + } + + class AutoDevAgent( + val api: API, + val session: Session, + val user: User?, + val ui: ApplicationInterface, + val model: ChatModel, + val parsingModel: ChatModel, + val event: AnActionEvent, + ) { + val actors = mapOf( + ActorTypes.DesignActor to ParsedActor( + resultClass = TaskList::class.java, + prompt = """ + Translate the user directive into an action plan for the project. + Break the user's request into a list of simple tasks to be performed. + For each task, provide a list of files to be modified and a description of the changes to be made. + """.trimIndent(), + model = model, + parsingModel = parsingModel, + ), + ActorTypes.TaskCodingActor to SimpleActor( + prompt = """ + Implement the changes to the codebase as described in the task list. + + Response should use one or more code patches in diff format within ```diff code blocks. + Each diff should be preceded by a header that identifies the file being modified. + The diff format should use + for line additions, - for line deletions. + The diff should include 2 lines of context before and after every change. + + Example: + + Here are the patches: + + ### src/utils/exampleUtils.js + ```diff + // Utility functions for example feature + const b = 2; + function exampleFunction() { + - return b + 1; + + return b + 2; + } + ``` + + ### tests/exampleUtils.test.js + ```diff + // Unit tests for exampleUtils + const assert = require('assert'); + const { exampleFunction } = require('../src/utils/exampleUtils'); + + describe('exampleFunction', () => { + - it('should return 3', () => { + + it('should return 4', () => { + assert.equal(exampleFunction(), 3); + }); + }); + ``` + """.trimIndent(), + model = model + ), + ).map { it.key.name to it.value }.toMap() + + enum class ActorTypes { + DesignActor, + TaskCodingActor, + } + + private val designActor by lazy { actors.get(ActorTypes.DesignActor.name)!! as ParsedActor } + private val taskActor by lazy { actors.get(ActorTypes.TaskCodingActor.name)!! as SimpleActor } + + fun start( + userMessage: String, + ) { + val codeFiles = mutableSetOf() + val root = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext) + ?.map { it.toFile.toPath() }?.toTypedArray()?.commonRoot()!! + PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext)?.forEach { file -> + // + codeFiles.add(root.relativize(file.toNioPath())) + } + require(codeFiles.isNotEmpty()) { "No files selected" } + fun codeSummary() = codeFiles.joinToString("\n\n") { path -> + "# $path\n```${ + path.toString().split('.').last() + }\n${root.resolve(path).toFile().readText()}\n```" + } + + val task = ui.newTask() + val api = (api as ChatClient).getChildClient().apply { + val createFile = task.createFile(".logs/api-${java.util.UUID.randomUUID()}.log") + createFile.second?.apply { + logStreams += this.outputStream().buffered() + task.verbose("API log: $this") + } + } + + val toInput = { it: String -> listOf(codeSummary(), it) } + val architectureResponse = Discussable( + task = task, + userMessage = { userMessage }, + heading = renderMarkdown(userMessage), + initialResponse = { it: String -> designActor.answer(toInput(it), api = api) }, + outputFn = { design: ParsedResponse -> + // renderMarkdown("${design.text}\n\n```json\n${JsonUtil.toJson(design.obj)/*.indent(" ")*/}\n```") + AgentPatterns.displayMapInTabs( + mapOf( + "Text" to renderMarkdown(design.text, ui = ui), + "JSON" to renderMarkdown("```json\n${toJson(design.obj)/*.indent(" ")*/}\n```", ui = ui), + ) + ) + }, + ui = ui, + reviseResponse = { userMessages: List> -> + designActor.respond( + messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } + .toTypedArray()), + input = toInput(userMessage), + api = api + ) + }, + atomicRef = AtomicReference(), + semaphore = Semaphore(0), + ).call() + + try { + val taskTabs = TabbedDisplay(task) + architectureResponse.obj.tasks.map { (paths, description) -> + var description = (description ?: UUID.random().toString()).trim() + // Strip `#` from the beginning of the description + while (description.startsWith("#")) { + description = description.substring(1) + } + description = renderMarkdown(description, ui = ui, tabs = false) + val task = ui.newTask(false).apply { taskTabs[description] = placeholder } + ApplicationServices.clientManager.getPool(session, user).submit { + task.header("Task: $description") + Retryable(ui, task) { + try { + val filter = codeFiles.filter { path -> + paths?.find { path.toString().contains(it) }?.isNotEmpty() == true + } + require(filter.isNotEmpty()) { + """ + No files found for """.trimIndent() + paths + """ + + Root: + """.trimIndent() + root + """ + + Files: + """.trimIndent() + codeFiles.joinToString("\n") + """ + + Paths: + """.trimIndent() + (paths?.joinToString("\n") ?: "") + } + renderMarkdown( + AddApplyFileDiffLinks.instrumentFileDiffs( + ui.socketManager!!, + root = root, + response = taskActor.answer( + listOf( + codeSummary(), + userMessage, + filter.joinToString("\n\n") { + "# ${it}\n```${ + it.toString().split('.').last().let { /*escapeHtml4*/it/*.indent(" ")*/ } + }\n${root.resolve(it).toFile().readText()}\n```" + }, + architectureResponse.text, + "Provide a change for ${paths?.joinToString(",") { it } ?: ""} ($description)" + ), api), + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + task.complete("$path Updated") + } + }, + ui = ui, + api = api + ) + ) + } catch (e: Exception) { + task.error(ui, e) + "" + } + } + } + }.toTypedArray().forEach { it.get() } + } catch (e: Exception) { + log.warn("Error", e) + } + } + } + + companion object { + private val log = LoggerFactory.getLogger(MultiStepPatchAction::class.java) + val root: File get() = File(AppSettingsState.instance.pluginHome, "code_chat") + + data class TaskList( + @Description("List of tasks to be performed in this project") + val tasks: List = emptyList() + ) : ValidatedObject { + override fun validate(): String? = when { + tasks.isEmpty() -> "Resources are required" + tasks.any { it.validate() != null } -> "Invalid resource" + else -> null + } + } + + data class Task( + @Description("List of paths involved in the task. This should include all files to be modified, and can include other files whose content will be informative in writing the changes.") + val paths: List? = null, + @Description("Detailed description of the changes to be made. Markdown format is supported.") + val description: String? = null + ) : ValidatedObject { + override fun validate(): String? = when { + paths.isNullOrEmpty() -> "Paths are required" + paths.any { it.isBlank() } -> "Invalid path" + else -> null + } + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/agent/OutlineAction.kt b/src/main/kotlin/aicoder/actions/agent/OutlineAction.kt new file mode 100644 index 00000000..3bb42d98 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/OutlineAction.kt @@ -0,0 +1,89 @@ +package aicoder.actions.agent + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.IdeaOpenAIClient +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.skyenet.apps.general.OutlineApp +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import java.text.SimpleDateFormat + +class OutlineAction : BaseAction() { + private var settings = OutlineSettings() + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + val project = e.project ?: return + val configDialog = OutlineConfigDialog(project, settings) + if (!configDialog.showAndGet()) return + settings = configDialog.settings + + try { + UITools.runAsync(project, "Initializing Outline Tool", true) { progress -> + progress.isIndeterminate = true + progress.text = "Setting up outline session..." + + val session = Session.newGlobalID() + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + val outlineApp = OutlineApp( + applicationName = "AI Outline Tool", + domainName = "outline", + api2 = IdeaOpenAIClient.instance, + settings = OutlineApp.Settings( + models = settings.expansionSteps.map { it.model }, + temperature = settings.temperature, + parsingModel = settings.parsingModel, + minTokensForExpansion = settings.minTokensForExpansion, + showProjector = settings.showProjector, + writeFinalEssay = settings.writeFinalEssay, + budget = settings.budget + ) + ) + + SessionProxyServer.chats[session] = outlineApp + + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "AI Outline Tool", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + + val server = AppServer.getServer(project) + val uri = server.server.uri.resolve("/#$session") + + ApplicationManager.getApplication().executeOnPooledThread { + try { + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + UITools.error(log, "Failed to open browser", e) + } + } + } + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + } + + override fun isEnabled(event: AnActionEvent) = true + + companion object { + private val log = LoggerFactory.getLogger(OutlineAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/agent/OutlineConfigDialog.kt b/src/main/kotlin/aicoder/actions/agent/OutlineConfigDialog.kt new file mode 100644 index 00000000..d8d3641c --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/OutlineConfigDialog.kt @@ -0,0 +1,212 @@ +package aicoder.actions.agent + +import aicoder.actions.ModelSelectionDialog +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.ui.ValidationInfo +import com.intellij.ui.components.JBList +import com.intellij.ui.dsl.builder.Align +import com.intellij.ui.dsl.builder.bindSelected +import com.intellij.ui.dsl.builder.panel +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.jopenai.models.chatModel +import javax.swing.* + +class OutlineConfigDialog( + val project: Project?, + var settings: OutlineSettings +) : DialogWrapper(project, true) { + + private var temperature = (settings.temperature * 100).toInt() + private var minTokens = settings.minTokensForExpansion + private var showProjector = settings.showProjector + private var writeFinalEssay = settings.writeFinalEssay + private var budget = settings.budget + private var parsingModel = settings.parsingModel + private val expansionSteps = DefaultListModel().apply { + settings.expansionSteps.forEach { addElement(it) } + } + private var selectedIndex = -1 + private val availableModels = ChatModel.values() + .map { it.value } + .filter { isVisible(it) } + .toList() + + init { + init() + title = "Configure Outline Tool" + } + + override fun createCenterPanel(): JComponent = panel { + group("Outline Generation Steps") { + row { + val listComponent = JBList(expansionSteps).apply { + cellRenderer = ListCellRenderer { list, value, index, isSelected, cellHasFocus -> + JLabel(value?.model?.modelName ?: "Unknown Model").apply { + if (isSelected) { + background = list.selectionBackground + foreground = list.selectionForeground + } + } + } + addListSelectionListener { e -> + if (!e.valueIsAdjusting) { + selectedIndex = selectedIndex + } + } + } + cell(listComponent) + .align(Align.FILL) + .comment("List of models to use in sequence for outline generation. At least one model is required.") + } + row { + this@group.buttonsGroup { + this@row.button("Add Step") { + val dialog = ModelSelectionDialog(project, availableModels) + if (dialog.showAndGet()) { + dialog.selectedModel?.let { model -> + expansionSteps.addElement(ExpansionStep(model)) + selectedIndex = expansionSteps.size() - 1 + } + } + } + this@row.button("Remove Step") { + if (selectedIndex >= 0) { + val newIndex = when { + selectedIndex > 0 -> selectedIndex - 1 + expansionSteps.size() > 1 -> 0 + else -> -1 + } + expansionSteps.remove(selectedIndex) + selectedIndex = newIndex + } + } + this@row.button("Edit Step") { + if (selectedIndex >= 0) { + val currentStep = expansionSteps.get(selectedIndex) + val dialog = ModelSelectionDialog(project, availableModels, currentStep.model) + if (dialog.showAndGet()) { + dialog.selectedModel?.let { model -> + expansionSteps.set(selectedIndex, ExpansionStep(model)) + } + } + } + } + } + } + } + group("Model Settings") { + row("Parsing Model:") { + comboBox(availableModels) + .apply { + component.selectedItem = parsingModel + component.addActionListener { + parsingModel = component.selectedItem as ChatModel + } + } + .align(Align.FILL) + .comment("Model used for parsing outline structure") + } + row("Min Tokens for Expansion:") { + intTextField() + .apply { + component.text = minTokens.toString() + component.addActionListener { + minTokens = component.text.toIntOrNull() ?: minTokens + } + } + .focused() + .comment("Minimum number of tokens required for section expansion") + } + } + row("Global Temperature:") { + slider( + min = 0, + max = 100, + minorTickSpacing = 1, + majorTickSpacing = 10, + ) + .apply { + component.value = temperature + component.addChangeListener { + temperature = component.value + } + } + .focused() + .comment("Adjust the temperature value (0-100)") + } + group("Output Settings") { + row { + checkBox("Show Projector") + .bindSelected({ showProjector }, { showProjector = it }) + .comment("Enable visualization of concept relationships") + } + row { + checkBox("Write Final Essay") + .bindSelected({ writeFinalEssay }, { writeFinalEssay = it }) + .comment("Generate a final essay from the outline") + } + } + group("Resource Settings") { + row("Budget:") { + cell(JSpinner(SpinnerNumberModel(budget, 0.1, 10.0, 0.1))) + .apply { + component.addChangeListener { + budget = component.value as Double + } + } + .align(Align.FILL) + .comment("Maximum budget in dollars") + } + } + } + + override fun doValidate(): ValidationInfo? { + if (expansionSteps.size() == 0) { + return ValidationInfo("At least one expansion step is required") + } + return null + } + + override fun doOKAction() { + settings = OutlineSettings( + expansionSteps = List(expansionSteps.size()) { expansionSteps.getElementAt(it) }, + temperature = temperature / 100.0, + minTokensForExpansion = minTokens, + showProjector = showProjector, + writeFinalEssay = writeFinalEssay, + budget = budget, + parsingModel = parsingModel + ) + super.doOKAction() + } + + companion object { + fun isVisible(model: ChatModel): Boolean { + val hasApiKey = AppSettingsState.instance.apiKey + ?.filter { it.value.isNotBlank() } + ?.keys + ?.contains(model.provider.name) + return false != hasApiKey + } + } +} + +data class ExpansionStep( + val model: ChatModel, +) + + +data class OutlineSettings( + val expansionSteps: List = listOf( + ExpansionStep(AppSettingsState.instance.smartModel.chatModel()), + ExpansionStep(AppSettingsState.instance.smartModel.chatModel()) + ), + val temperature: Double = AppSettingsState.instance.temperature, + val minTokensForExpansion: Int = 16, + val showProjector: Boolean = true, + val writeFinalEssay: Boolean = true, + val budget: Double = 2.0, + val parsingModel: ChatModel = AppSettingsState.instance.smartModel.chatModel() +) \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/agent/ShellCommandAction.kt b/src/main/kotlin/aicoder/actions/agent/ShellCommandAction.kt new file mode 100644 index 00000000..c0826361 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/ShellCommandAction.kt @@ -0,0 +1,169 @@ +package aicoder.actions.agent + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.progress.ProgressIndicator +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.apps.code.CodingAgent +import com.simiacryptus.skyenet.core.actors.CodingActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.interpreter.ProcessInterpreter +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.session.SessionTask +import java.text.SimpleDateFormat + +class ShellCommandAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent): Boolean { + return UITools.getSelectedFolder(event) != null + } + + override fun handle(e: AnActionEvent) { + val project = e.project ?: return + UITools.runAsync(project, "Initializing Shell Command", true) { progress -> + try { + initializeShellCommand(e, progress) + } catch (ex: Exception) { + log.error("Failed to initialize shell command", ex) + UITools.showErrorDialog( + "Failed to initialize shell command: ${ex.message}", + "Error" + ) + } + } + } + + private fun initializeShellCommand(e: AnActionEvent, progress: ProgressIndicator) { + progress.text = "Setting up shell environment..." + val selectedFolder = UITools.getSelectedFolder(e)?.toFile ?: throw IllegalStateException("No directory selected") + progress.text = "Configuring session..." + val session = Session.newGlobalID() + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = object : ApplicationServer( + applicationName = "Shell Agent", + path = "/shellAgent", + showMenubar = false, + ) { + override val singleInput = true + override val stickyInput = false + + + override fun userMessage( + session: Session, + user: User?, + userMessage: String, + ui: ApplicationInterface, + api: API + ) { + progress.text = "Processing command..." + val task = ui.newTask() + val agent = object : CodingAgent( + api = api, + dataStorage = dataStorage, + session = session, + user = user, + ui = ui, + interpreter = ProcessInterpreter::class, + symbols = mapOf( + "workingDir" to selectedFolder.absolutePath, + "language" to if (isWindows) "powershell" else "bash", + "command" to listOf(AppSettingsState.instance.shellCommand) + ), + temperature = AppSettingsState.instance.temperature, + details = """ + Execute the following shell command(s) in the specified directory and provide the output. + Guidelines: + - Handle errors and exceptions gracefully + - Provide clear output formatting + - Support command cancellation + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel(), + mainTask = task, + ) { + override fun displayFeedback( + task: SessionTask, + request: CodingActor.CodeRequest, + response: CodingActor.CodeResult + ) { + val formText = StringBuilder() + var formHandle: StringBuilder? = null + formHandle = task.add( + "
\n${ + if (!super.canPlay) "" else super.playButton( + task, + request, + response, + formText + ) { formHandle!! } + }\n${ + acceptButton( + task, + request, + response, + formText + ) { formHandle!! } + }\n
\n${super.reviseMsg(task, request, response, formText) { formHandle!! }}", additionalClasses = "reply-message" + ) + formText.append(formHandle.toString()) + formHandle.toString() + task.complete() + } + + fun acceptButton( + task: SessionTask, + request: CodingActor.CodeRequest, + response: CodingActor.CodeResult, + formText: StringBuilder, + formHandle: () -> StringBuilder + ): String { + return ui.hrefLink("Accept", "href-link play-button") { + } + } + }.apply { + this.start(userMessage) + } + } + } + progress.text = "Opening browser interface..." + + val server = AppServer.getServer(e.project) + + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Exception) { + log.warn("Error opening browser", e) + } + }.start() + } + + companion object { + private val isWindows = System.getProperty("os.name").lowercase().contains("windows") + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/agent/SimpleCommandAction.kt b/src/main/kotlin/aicoder/actions/agent/SimpleCommandAction.kt new file mode 100644 index 00000000..d532679c --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/SimpleCommandAction.kt @@ -0,0 +1,390 @@ +package aicoder.actions.agent + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.diff.AddApplyFileDiffLinks +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.describe.Description +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.AgentPatterns +import com.simiacryptus.skyenet.Retryable +import com.simiacryptus.skyenet.core.actors.ParsedActor +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.core.util.FileValidationUtils +import com.simiacryptus.skyenet.core.util.FileValidationUtils.Companion.filteredWalk +import com.simiacryptus.skyenet.core.util.FileValidationUtils.Companion.isGitignore +import com.simiacryptus.skyenet.core.util.FileValidationUtils.Companion.isLLMIncludableFile +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.session.SessionTask +import com.simiacryptus.util.JsonUtil +import org.slf4j.LoggerFactory +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.text.SimpleDateFormat +import kotlin.io.path.ExperimentalPathApi +import kotlin.io.path.walk + +class SimpleCommandAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(event: AnActionEvent) { + val project = event.project + try { + val settings = getUserSettings(event) ?: run { + log.error("Failed to retrieve user settings") + UITools.showErrorDialog("Failed to retrieve settings", "Error") + return + } + UITools.run(project, "Initializing", true) { progress -> + progress.text = "Setting up command execution..." + val dataContext = event.dataContext + val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) + val folder = UITools.getSelectedFolder(event) + val root = folder?.toFile?.toPath() ?: project?.basePath?.let { File(it).toPath() } ?: run { + throw IllegalStateException("Failed to determine project root") + } + + val session = Session.newGlobalID() + progress.text = "Creating patch application..." + val patchApp = createPatchApp(root.toFile(), session, settings, virtualFiles) + progress.text = "Configuring session..." + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = patchApp + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + val server = AppServer.getServer(project) + openBrowserWithDelay(server.server.uri.resolve("/#$session")) + } + + } catch (e: Exception) { + log.error("Error handling action", e) + UITools.showErrorDialog( + "Failed to execute command: ${e.message}", + "Error" + ) + } + } + + private fun createPatchApp( + root: File, + session: Session, + settings: Settings, + virtualFiles: Array? + ): PatchApp = UITools.run(null, "Creating Patch Application", true) { progress -> + progress.text = "Initializing patch application..." + object : PatchApp(root, session, settings) { + // Limit file size to 0.5MB for performance + private val maxFileSize = 512 * 1024 + + override fun codeFiles() = (virtualFiles?.toList()?.flatMap { + FileValidationUtils.expandFileList(it.toFile).toList() + }?.map { it.toPath() }?.toSet()?.toMutableSet() ?: mutableSetOf()) + .filter { it.toFile().length() < maxFileSize } + .map { root.toPath().relativize(it) ?: it }.toSet() + // Add progress indication for long operations + + override fun codeSummary(paths: List) = paths + .filter { it.toFile().exists() } + .mapIndexed { index, path -> + progress.fraction = index.toDouble() / paths.size + progress.text = "Processing ${path.fileName}..." + if (progress.isCanceled) throw InterruptedException("Operation cancelled") + "# ${settings.workingDirectory.toPath().relativize(path)}\n$tripleTilde${path.toString().split('.').lastOrNull()}\n${ + path.toFile().readText(Charsets.UTF_8) + }\n$tripleTilde" + }.joinToString("\n\n") + // Add validation for file operations + + override fun projectSummary() = codeFiles() + .asSequence() + .filter { settings.workingDirectory.toPath()?.resolve(it)?.toFile()?.exists() == true } + .distinct().sorted() + .joinToString("\n") { path -> + "* ${path} - ${ + settings.workingDirectory.toPath()?.resolve(path)?.toFile()?.length() ?: "?" + } bytes".trim() + } + + override fun searchFiles(searchStrings: List): Set { + require(searchStrings.isNotEmpty()) { "Search strings cannot be empty" } + return searchStrings.flatMap { searchString -> + filteredWalk(settings.workingDirectory) { !isGitignore(it.toPath()) } + .filter { isLLMIncludableFile(it) } + .filter { it.readText().contains(searchString, ignoreCase = true) } + .map { it.toPath() } + .toList() + }.toSet() + } + } + } + // Add proper resource cleanup + + private fun openBrowserWithDelay(uri: java.net.URI) { + Thread({ + Thread.sleep(500) + try { + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + UITools.showErrorDialog("Failed to open browser: ${e.message}", "Error") + } + }, "BrowserOpener").apply { isDaemon = true }.start() + } + + abstract inner class PatchApp( + override val root: File, + val session: Session, + val settings: Settings, + ) : ApplicationServer( + applicationName = "Magic Code Genie", + path = "/doCmd", + showMenubar = false, + ) { + abstract fun codeFiles(): Set + abstract fun codeSummary(paths: List): String + abstract fun searchFiles(searchStrings: List): Set + override val singleInput = true + override val stickyInput = false + + override fun userMessage( + session: Session, + user: User?, + userMessage: String, + ui: ApplicationInterface, + api: API + ) { + val task = ui.newTask() + task.echo(renderMarkdown(userMessage)) + Thread { + run(ui, task, session, settings, userMessage) + }.start() + task.placeholder + } + + abstract fun projectSummary(): String + } + + private fun PatchApp.run( + ui: ApplicationInterface, + task: SessionTask, + session: Session, + settings: Settings, + userMessage: String = "" + ) { + try { + val planTxt = projectSummary() + task.verbose(renderMarkdown(planTxt)) + Retryable(ui, task) { + val plan = ParsedActor( + resultClass = ParsedTasks::class.java, + prompt = """ + You are a helpful AI that helps people with coding. + + You will be answering questions about the following project: + + Project Root: """.trimIndent() + (settings.workingDirectory.absolutePath ?: "") + """ + + Files: + """.trimIndent() + planTxt + """ + + Given the request, identify one or more tasks. + For each task: + 1) predict the files that need to be fixed + 2) predict related files that may be needed to debug the issue + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel() + ).answer( + listOf( + "\nExecute the following directive:\n\n$tripleTilde\n$userMessage\n$tripleTilde\n" + ), api = api + ) + val progressHeader = task.header("Processing tasks") + plan.obj.errors?.forEach { planTask -> + Retryable(ui, task) { + val paths = + ((planTask.fixFiles ?: emptyList()) + (planTask.relatedFiles ?: emptyList())).flatMap { + toPaths(settings.workingDirectory.toPath(), it) + } + val searchResults = searchFiles(planTask.searchStrings ?: emptyList()) + val combinedPaths = (paths + searchResults).distinct() + val prunedPaths = prunePaths(combinedPaths, 50 * 1024) + val codeSummary = + codeSummary(prunedPaths.map { settings.workingDirectory.toPath().resolve(it) }) + val response = SimpleActor( + prompt = """ + You are a helpful AI that helps people with coding. + + You will be answering questions about the following code: + + """.trimIndent() + codeSummary + """ + + + Response should use one or more code patches in diff format within """.trimIndent() + tripleTilde + """diff code blocks. + Each diff should be preceded by a header that identifies the file being modified. + The diff format should use + for line additions, - for line deletions. + The diff should include 2 lines of context before and after every change. + + Example: + + Here are the patches: + + ### src/utils/exampleUtils.js + """.trimIndent() + tripleTilde + """diff + // Utility functions for example feature + const b = 2; + function exampleFunction() { + - return b + 1; + + return b + 2; + } + """.trimIndent() + tripleTilde + """ + + ### tests/exampleUtils.test.js + """.trimIndent() + tripleTilde + """diff + // Unit tests for exampleUtils + const assert = require('assert'); + const { exampleFunction } = require('../src/utils/exampleUtils'); + + describe('exampleFunction', () => { + - it('should return 3', () => { + + it('should return 4', () => { + assert.equal(exampleFunction(), 3); + }); + }); + """.trimIndent() + tripleTilde + """ + + If needed, new files can be created by using code blocks labeled with the filename in the same manner. + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel() + ).answer( + listOf( + "We are working on executing the following directive:\n\n$tripleTilde\n$userMessage\n$tripleTilde\n\nFocus on the task at hand:\n ${ + planTask.message?.replace( + "\n", + "\n " + ) ?: "" + }" + ), api = api + ) + val markdown = AddApplyFileDiffLinks.instrumentFileDiffs( + ui.socketManager!!, + root = root.toPath(), + response = response, + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + task.complete("$path Updated") + } + }, + ui = ui, + api = api, + ) + "
${renderMarkdown(markdown!!)}
" + } + } + progressHeader?.clear() + //task.append("", false) + AgentPatterns.displayMapInTabs( + mapOf( + "Text" to renderMarkdown(plan.text, ui = ui), + "JSON" to renderMarkdown( + "${tripleTilde}json\n${JsonUtil.toJson(plan.obj)}\n$tripleTilde", + ui = ui + ), + ) + ) + } + } catch (e: Exception) { + log.error("Error during task execution", e) + task.error(ui, e) + } + } + + private fun prunePaths(paths: List, maxSize: Int): List { + val sortedPaths = paths.sortedByDescending { it.toFile().length() } + var totalSize = 0 + val prunedPaths = mutableListOf() + for (path in sortedPaths) { + val fileSize = path.toFile().length().toInt() + if (totalSize + fileSize > maxSize) break + prunedPaths.add(path) + totalSize += fileSize + } + return prunedPaths + } + + data class ParsedTasks( + val errors: List? = null + ) + + data class ParsedTask( + @Description("The task to be performed") + val message: String? = null, + @Description("Files identified as needing modification and issue-related files, in order of descending relevance") + val relatedFiles: List? = null, + @Description("Files identified as needing modification and issue-related files, in order of descending relevance") + val fixFiles: List? = null, + @Description("Search strings to find relevant files, in order of descending relevance") + val searchStrings: List? = null + ) + + data class Settings( + var workingDirectory: File, + ) + + private fun getUserSettings(event: AnActionEvent?): Settings? { + val root = UITools.getSelectedFolder(event ?: return null)?.toNioPath() ?: event.project?.basePath?.let { + File(it).toPath() + } + val files = UITools.getSelectedFiles(event).map { it.path.let { File(it).toPath() } }.toMutableSet() + if (files.isEmpty()) Files.walk(root) + .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } + .toList().filterNotNull().forEach { files.add(it) } + return root?.toFile()?.let { Settings(it) } + } + + override fun isEnabled(event: AnActionEvent) = true + + companion object { + private val log = LoggerFactory.getLogger(SimpleCommandAction::class.java) + val tripleTilde = "`" + "``" // This is a workaround for the markdown parser when editing this file + + @OptIn(ExperimentalPathApi::class) + fun toPaths(root: Path, it: String): Iterable { + // Expand any wildcards + return if (it.contains("*")) { + val prefix = it.substringBefore("*") + val suffix = it.substringAfter("*") + val files = root.walk().toList() + files.filter { + it.toString().startsWith(prefix) && it.toString().endsWith(suffix) + } + } else { + listOf(Path.of(it)) + } + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/agent/WebDevelopmentAssistantAction.kt b/src/main/kotlin/aicoder/actions/agent/WebDevelopmentAssistantAction.kt new file mode 100644 index 00000000..7c234adc --- /dev/null +++ b/src/main/kotlin/aicoder/actions/agent/WebDevelopmentAssistantAction.kt @@ -0,0 +1,673 @@ +package aicoder.actions.agent + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.IdeaOpenAIClient +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.diff.AddApplyFileDiffLinks + +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.OpenAIClient +import com.simiacryptus.jopenai.describe.Description +import com.simiacryptus.jopenai.models.ApiModel +import com.simiacryptus.jopenai.models.ApiModel.Role +import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.jopenai.models.ImageModels +import com.simiacryptus.jopenai.models.OpenAIModels +import com.simiacryptus.jopenai.proxy.ValidatedObject +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import com.simiacryptus.skyenet.AgentPatterns +import com.simiacryptus.skyenet.Discussable +import com.simiacryptus.skyenet.TabbedDisplay +import com.simiacryptus.skyenet.core.actors.* +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.file.DataStorage +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.session.SessionTask +import com.simiacryptus.util.JsonUtil +import org.slf4j.LoggerFactory +import java.io.ByteArrayOutputStream +import java.io.File +import java.nio.file.Path +import java.text.SimpleDateFormat +import java.util.concurrent.Semaphore +import java.util.concurrent.atomic.AtomicReference +import javax.imageio.ImageIO +import kotlin.io.path.name + +val VirtualFile.toFile: File get() = File(this.path) + +class WebDevelopmentAssistantAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val file = UITools.getSelectedFile(event) ?: return false + return file.isDirectory + } + + + override fun handle(e: AnActionEvent) { + try { + val project = e.project ?: return + val session = Session.newGlobalID() + val selectedFile = UITools.getSelectedFolder(e) ?: return + DataStorage.sessionPaths[session] = selectedFile.toFile + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = WebDevApp(root = selectedFile) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + val server = AppServer.getServer(project) + + UITools.runAsync(e.project, "Opening Web Development Assistant", true) { progress -> + progress.text = "Launching browser..." + Thread.sleep(500) + + val uri = server.server.uri.resolve("/#$session") + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } + } catch (e: Throwable) { + UITools.error(log, "Error launching Web Development Assistant", e) + } + } + + + open class WebDevApp( + applicationName: String = "Web Development Agent", + val temperature: Double = 0.1, + root: VirtualFile?, + override val singleInput: Boolean = false, + ) : ApplicationServer( + applicationName = applicationName, + path = "/webdev", + showMenubar = false, + root = root?.toFile!!, + ) { + private val log = LoggerFactory.getLogger(WebDevApp::class.java) + + companion object { + private const val DEFAULT_BUDGET = 2.00 + } + + override fun userMessage( + session: Session, + user: User?, + userMessage: String, + ui: ApplicationInterface, + api: API + ) { + try { + val settings = getSettings(session, user) ?: Settings() + if (api is ChatClient) { + api.budget = settings.budget ?: DEFAULT_BUDGET + } + WebDevAgent( + api = api, + api2 = IdeaOpenAIClient.instance, + session = session, + user = user, + ui = ui, + model = settings.model, + parsingModel = settings.parsingModel, + tools = settings.tools, + root = root, + ).start(userMessage = userMessage) + } catch (e: Throwable) { + log.error("Error processing user message", e) + throw e + } + } + + data class Settings( + val budget: Double? = 2.00, + val tools: List = emptyList(), + val model: ChatModel = OpenAIModels.GPT4o, + val parsingModel: ChatModel = OpenAIModels.GPT4oMini, + ) + + override val settingsClass: Class<*> get() = Settings::class.java + + @Suppress("UNCHECKED_CAST") + override fun initSettings(session: Session): T? = Settings() as T + } + + class WebDevAgent( + val api: API, + val api2: OpenAIClient, + val session: Session, + val user: User?, + val ui: ApplicationInterface, + val model: ChatModel, + val parsingModel: ChatModel, + val tools: List = emptyList(), + val root: File, + ) { + val actors = mapOf( + ActorTypes.ArchitectureDiscussionActor to ParsedActor( + resultClass = ProjectSpec::class.java, + prompt = """ + Translate the user's idea into a detailed architecture for a simple web application. + + List all html, css, javascript, and image files to be created, and for each file: + 1. Mark with filename tags. + 2. Describe the public interface / interaction with other components. + 3. Core functional requirements. + + Specify user interactions and how the application will respond to them. + Identify key HTML classes and element IDs that will be used to bind the application to the HTML. + """.trimIndent(), + model = model, + parsingModel = parsingModel, + ), + ActorTypes.CodeReviewer to SimpleActor( + prompt = """ + Analyze the code summarized in the user's header-labeled code blocks. + Review, look for bugs, and provide fixes. + Provide implementations for missing functions. + + Response should use one or more code patches in diff format within ```diff code blocks. + Each diff should be preceded by a header that identifies the file being modified. + The diff format should use + for line additions, - for line deletions. + The diff should include 2 lines of context before and after every change. + + Example: + + Here are the patches: + + ### src/utils/exampleUtils.js + ```diff + // Utility functions for example feature + const b = 2; + function exampleFunction() { + - return b + 1; + + return b + 2; + } + ``` + + ### tests/exampleUtils.test.js + ```diff + // Unit tests for exampleUtils + const assert = require('assert'); + const { exampleFunction } = require('../src/utils/exampleUtils'); + + describe('exampleFunction', () => { + - it('should return 3', () => { + + it('should return 4', () => { + assert.equal(exampleFunction(), 3); + }); + }); + ``` + """.trimIndent(), + model = model, + ), + ActorTypes.HtmlCodingActor to SimpleActor( + prompt = """ + You will translate the user request into a skeleton HTML file for a rich javascript application. + The html file can reference needed CSS and JS files, which are will be located in the same directory as the html file. + Do not output the content of the resource files, only the html file. + """.trimIndent(), model = model + ), + ActorTypes.JavascriptCodingActor to SimpleActor( + prompt = """ + You will translate the user request into a javascript file for use in a rich javascript application. + """.trimIndent(), model = model + ), + ActorTypes.CssCodingActor to SimpleActor( + prompt = """ + You will translate the user request into a CSS file for use in a rich javascript application. + """.trimIndent(), model = model + ), + ActorTypes.EtcCodingActor to SimpleActor( + prompt = """ + You will translate the user request into a file for use in a web application. + """.trimIndent(), + model = model, + ), + ActorTypes.ImageActor to ImageActor( + prompt = """ + You will translate the user request into an image file for use in a web application. + """.trimIndent(), + textModel = model, + imageModel = ImageModels.DallE3, + ).apply { + setImageAPI(api2) + }, + ).map { it.key.name to it.value }.toMap() + + enum class ActorTypes { + HtmlCodingActor, + JavascriptCodingActor, + CssCodingActor, + ArchitectureDiscussionActor, + CodeReviewer, + EtcCodingActor, + ImageActor, + } + + private val architectureDiscussionActor by lazy { actors.get(ActorTypes.ArchitectureDiscussionActor.name)!! as ParsedActor } + private val htmlActor by lazy { actors.get(ActorTypes.HtmlCodingActor.name)!! as SimpleActor } + private val imageActor by lazy { actors.get(ActorTypes.ImageActor.name)!! as ImageActor } + private val javascriptActor by lazy { actors.get(ActorTypes.JavascriptCodingActor.name)!! as SimpleActor } + private val cssActor by lazy { actors.get(ActorTypes.CssCodingActor.name)!! as SimpleActor } + private val codeReviewer by lazy { actors.get(ActorTypes.CodeReviewer.name)!! as SimpleActor } + private val etcActor by lazy { actors.get(ActorTypes.EtcCodingActor.name)!! as SimpleActor } + + private val codeFiles = mutableSetOf() + + fun start( + userMessage: String, + ) { + val task = ui.newTask() + val toInput = { it: String -> listOf(it) } + val architectureResponse = Discussable( + task = task, + userMessage = { userMessage }, + initialResponse = { it: String -> architectureDiscussionActor.answer(toInput(it), api = api) }, + outputFn = { design: ParsedResponse -> + // renderMarkdown("${design.text}\n\n```json\n${JsonUtil.toJson(design.obj)/*.indent(" ")*/}\n```") + AgentPatterns.displayMapInTabs( + mapOf( + "Text" to renderMarkdown(design.text, ui = ui), + "JSON" to renderMarkdown( + "```json\n${JsonUtil.toJson(design.obj)/*.indent(" ")*/}\n```", + ui = ui + ), + ) + ) + }, + ui = ui, + reviseResponse = { userMessages: List> -> + architectureDiscussionActor.respond( + messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } + .toTypedArray()), + input = toInput(userMessage), + api = api + ) + }, + atomicRef = AtomicReference(), + semaphore = Semaphore(0), + heading = renderMarkdown(userMessage) + ).call() + + + try { +// val toolSpecs = tools.map { ToolServlet.tools.find { t -> t.path == it } } +// .joinToString("\n\n") { it?.let { JsonUtil.toJson(it.openApiDescription) } ?: "" } + var messageWithTools = userMessage +// if (toolSpecs.isNotBlank()) messageWithTools += "\n\nThese services are available:\n$toolSpecs" + task.echo( + renderMarkdown( + "```json\n${JsonUtil.toJson(architectureResponse.obj)/*.indent(" ")*/}\n```", + ui = ui + ) + ) + val fileTabs = TabbedDisplay(task) + architectureResponse.obj.files.filter { + !it.name!!.startsWith("http") + }.map { (path, description) -> + val task = ui.newTask(false).apply { fileTabs[path.toString()] = placeholder } + task.header("Drafting $path") + codeFiles.add(File(path).toPath()) + ApplicationServices.clientManager.getPool(session, user).submit { + when (path!!.split(".").last().lowercase()) { + + "js" -> draftResourceCode( + task = task, + request = javascriptActor.chatMessages( + listOf( + messageWithTools, + architectureResponse.text, + "Render $path - $description" + ) + ), + actor = javascriptActor, + path = File(path).toPath(), "js", "javascript" + ) + + + "css" -> draftResourceCode( + task = task, + request = cssActor.chatMessages( + listOf( + messageWithTools, + architectureResponse.text, + "Render $path - $description" + ) + ), + actor = cssActor, + path = File(path).toPath() + ) + + "html" -> draftResourceCode( + task = task, + request = htmlActor.chatMessages( + listOf( + messageWithTools, + architectureResponse.text, + "Render $path - $description" + ) + ), + actor = htmlActor, + path = File(path).toPath() + ) + + "png" -> draftImage( + task = task, + request = etcActor.chatMessages( + listOf( + messageWithTools, + architectureResponse.text, + "Render $path - $description" + ) + ), + actor = imageActor, + path = File(path).toPath() + ) + + "jpg" -> draftImage( + task = task, + request = etcActor.chatMessages( + listOf( + messageWithTools, + architectureResponse.text, + "Render $path - $description" + ) + ), + actor = imageActor, + path = File(path).toPath() + ) + + else -> draftResourceCode( + task = task, + request = etcActor.chatMessages( + listOf( + messageWithTools, + architectureResponse.text, + "Render $path - $description" + ) + ), + actor = etcActor, + path = File(path).toPath() + ) + + } + } + }.toTypedArray().forEach { it.get() } + // Apply codeReviewer + + iterateCode(task) + } catch (e: Throwable) { + log.warn("Error", e) + task.error(ui, e) + } + } + + fun codeSummary() = codeFiles.filter { + if (it.name.lowercase().endsWith(".png")) return@filter false + if (it.name.lowercase().endsWith(".jpg")) return@filter false + true + }.joinToString("\n\n") { path -> + "# $path\n```${path.toString().split('.').last()}\n${root.resolve(path.toFile()).readText()}\n```" + } + + private fun iterateCode( + task: SessionTask + ) { + Discussable( + task = task, + heading = "Code Refinement", + userMessage = { codeSummary() }, + initialResponse = { + codeReviewer.answer(listOf(it), api = api) + }, + outputFn = { code -> + renderMarkdown( + AddApplyFileDiffLinks.instrumentFileDiffs( + ui.socketManager!!, + root = root.toPath(), + response = code, + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + task.complete("$path Updated") + } + }, + ui = ui, + api = api + ) + ) + }, + ui = ui, + reviseResponse = { userMessages -> + val userMessages = userMessages.toMutableList() + userMessages.set(0, userMessages.get(0).copy(first = codeSummary())) + val combinedMessages = + userMessages.map { ApiModel.ChatMessage(Role.user, it.first.toContentList()) } + codeReviewer.respond( + input = listOf(element = combinedMessages.joinToString("\n")), + api = api, + messages = combinedMessages.toTypedArray(), + ) + }, + ).call() + } + + private fun draftImage( + task: SessionTask, + request: Array, + actor: ImageActor, + path: Path, + ) { + try { + var code = Discussable( + task = task, + userMessage = { "" }, + heading = "Drafting $path", + initialResponse = { + val messages = (request + ApiModel.ChatMessage(Role.user, "Draft $path".toContentList())) + .toList().toTypedArray() + actor.respond( + listOf(request.joinToString("\n") { it.content?.joinToString() ?: "" }), + api, + *messages + ) + + }, + outputFn = { img -> + renderMarkdown( + "", ui = ui + ) + }, + ui = ui, + reviseResponse = { userMessages: List> -> + actor.respond( + messages = (request.toList() + userMessages.map { + ApiModel.ChatMessage( + it.second, + it.first.toContentList() + ) + }) + .toTypedArray(), + input = listOf( + element = (request.toList() + userMessages.map { + ApiModel.ChatMessage( + it.second, + it.first.toContentList() + ) + }) + .joinToString("\n") { it.content?.joinToString() ?: "" }), + api = api, + ) + }, + ).call() + task.complete( + renderMarkdown( + "", ui = ui + ) + ) + } catch (e: Throwable) { + val error = task.error(ui, e) + task.complete(ui.hrefLink("♻", "href-link regen-button") { + error?.clear() + draftImage(task, request, actor, path) + }) + } + } + + private fun write( + code: ImageResponse, + path: Path + ): ByteArray { + val byteArrayOutputStream = ByteArrayOutputStream() + ImageIO.write( + code.image, + path.toString().split(".").last(), + byteArrayOutputStream + ) + val bytes = byteArrayOutputStream.toByteArray() + return bytes + } + + private fun draftResourceCode( + task: SessionTask, + request: Array, + actor: SimpleActor, + path: Path, + vararg languages: String = arrayOf(path.toString().split(".").last().lowercase()), + ) { + try { + var code = Discussable( + task = task, + userMessage = { "Drafting $path" }, + heading = "", + initialResponse = { + actor.respond( + listOf(request.joinToString("\n") { it.content?.joinToString() ?: "" }), + api, + *(request + ApiModel.ChatMessage(Role.user, "Draft $path".toContentList())) + .toList().toTypedArray() + ) + }, + outputFn = { design: String -> + var design = design + languages.forEach { language -> + if (design.contains("```$language")) { + design = design.substringAfter("```$language").substringBefore("```") + } + } + renderMarkdown("```${languages.first()}\n${design.let { it }}\n```", ui = ui) + }, + ui = ui, + reviseResponse = { userMessages: List> -> + actor.respond( + messages = (request.toList() + userMessages.map { + ApiModel.ChatMessage( + it.second, + it.first.toContentList() + ) + }) + .toTypedArray(), + input = listOf( + element = (request.toList() + userMessages.map { + ApiModel.ChatMessage( + it.second, + it.first.toContentList() + ) + }) + .joinToString("\n") { it.content?.joinToString() ?: "" }), + api = api, + ) + }, + ).call() + code = extractCode(code) + task.complete( + "$path Updated" + ) + } catch (e: Throwable) { + val error = task.error(ui, e) + task.complete(ui.hrefLink("♻", "href-link regen-button") { + error?.clear() + draftResourceCode(task, request, actor, path, *languages) + }) + } + } + + private fun extractCode(code: String): String { + var code = code + code = code.trim() + "(?s)```[^\\n]*\n(.*)\n```".toRegex().find(code)?.let { + code = it.groupValues[1] + } + return code + } + + } + + companion object { + private val log = LoggerFactory.getLogger(WebDevelopmentAssistantAction::class.java) + val root: File get() = File(AppSettingsState.instance.pluginHome, "code_chat") + + data class ProjectSpec( + @Description("Files in the project design, including all local html, css, and js files.") + val files: List = emptyList() + ) : ValidatedObject { + override fun validate(): String? = when { + files.isEmpty() -> "Resources are required" + files.any { it.validate() != null } -> "Invalid resource" + else -> null + } + } + + data class ProjectFile( + @Description("The path to the file, relative to the project root.") + val name: String? = "", + @Description("A brief description of the file's purpose and contents.") + val description: String? = "" + ) : ValidatedObject { + override fun validate(): String? = when { + name.isNullOrBlank() -> "Path is required" + name.contains(" ") -> "Path cannot contain spaces" + !name.contains(".") -> "Path must contain a file extension" + else -> null + } + } + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/chat/CodeChatAction.kt b/src/main/kotlin/aicoder/actions/chat/CodeChatAction.kt new file mode 100644 index 00000000..cd0e835f --- /dev/null +++ b/src/main/kotlin/aicoder/actions/chat/CodeChatAction.kt @@ -0,0 +1,73 @@ +package aicoder.actions.chat + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.CodeChatSocketManager +import com.simiacryptus.aicoder.util.LanguageUtils +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import java.text.SimpleDateFormat + +class CodeChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + val editor = e.getData(CommonDataKeys.EDITOR) ?: return + + val session = Session.newGlobalID() + val language = LanguageUtils.getComputerLanguage(e)?.name ?: "" + val filename = FileDocumentManager.getInstance().getFile(editor.document)?.name ?: return + + SessionProxyServer.agents[session] = CodeChatSocketManager( + session = session, + language = language, + codeSelection = editor.caretModel.primaryCaret.selectedText ?: editor.document.text, + filename = filename, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + val server = AppServer.getServer(e.project) + + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + override fun isEnabled(event: AnActionEvent) = true + + companion object { + private val log = LoggerFactory.getLogger(CodeChatAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/chat/DiffChatAction.kt b/src/main/kotlin/aicoder/actions/chat/DiffChatAction.kt new file mode 100644 index 00000000..fb7b623b --- /dev/null +++ b/src/main/kotlin/aicoder/actions/chat/DiffChatAction.kt @@ -0,0 +1,199 @@ +package aicoder.actions.chat + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.util.TextRange +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.CodeChatSocketManager +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.diff.AddApplyDiffLinks.Companion.addApplyDiffLinks +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.session.SessionTask +import org.intellij.lang.annotations.Language +import org.slf4j.LoggerFactory +import java.text.SimpleDateFormat +import com.intellij.openapi.application.ApplicationManager as IntellijAppManager + +class DiffChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + val path = "/diffChat" + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val editor = event.getData(CommonDataKeys.EDITOR) ?: return false + val document = editor.document + return FileDocumentManager.getInstance().getFile(document) != null + } + + + override fun handle(e: AnActionEvent) { + try { + val editor = e.getData(CommonDataKeys.EDITOR) ?: return + val session = Session.newGlobalID() + val language = ComputerLanguage.getComputerLanguage(e)?.name ?: "" + val document = editor.document + val filename = FileDocumentManager.getInstance().getFile(document)?.name ?: return + val (rawText, selectionStart, selectionEnd) = getSelectionDetails(editor) + UITools.runAsync(e.project, "Initializing Chat", true) { progress -> + progress.isIndeterminate = true + progress.text = "Setting up chat session..." + setupApplicationServer(session) + setupSessionProxy(session, language, rawText, filename, editor, selectionStart, selectionEnd, document) + openBrowserWindow(e, session) + } + } catch (ex: Throwable) { + log.error("Error in DiffChat action", ex) + UITools.showErrorDialog("Failed to initialize chat: ${ex.message}", "Error") + } + } + + private fun getSelectionDetails(editor: Editor): Triple { + val primaryCaret = editor.caretModel.primaryCaret + val selectedText = primaryCaret.selectedText + return if (selectedText != null) { + Triple( + selectedText.toString(), + primaryCaret.selectionStart, + primaryCaret.selectionEnd + ) + } else { + Triple( + editor.document.text, + 0, + editor.document.text.length + ) + } + } + + private fun setupApplicationServer(session: Session) { + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + } + + private fun setupSessionProxy( + session: Session, + language: String, + rawText: String, + filename: String, + editor: Editor, + selectionStart: Int, + selectionEnd: Int, + document: Document + ) { + var selectionEnd = selectionEnd + + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.agents[session] = object : CodeChatSocketManager( + session = session, + language = language, + codeSelection = rawText, + filename = filename, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) + ) { + + // ... rest of the implementation + override val systemPrompt: String + @Language("Markdown") + get() = super.systemPrompt + """ + Please provide code modifications in the following diff format within triple-backtick diff code blocks. Each diff block should be preceded by a header that identifies the file being modified. + + The diff format rules are as follows: + - Use '-' at the beginning of a line to indicate a deletion. + - Use '+' at the beginning of a line to indicate an addition. + - Include 2 lines of context before and after every change to help identify the location of the change. + - If a line is part of the original code and hasn't been modified, simply include it without '+' or '-'. + - Lines starting with "@@" or "---" or "+++" are treated as headers and are ignored. + + Example: + + Here are the patches: + + ### src/utils/exampleUtils.js + ```diff + // Utility functions for example feature + const b = 2; + function exampleFunction() { + - return b + 1; + + return b + 2; + } + ``` + + ### tests/exampleUtils.test.js + ```diff + // Unit tests for exampleUtils + const assert = require('assert'); + const { exampleFunction } = require('../src/utils/exampleUtils'); + + describe('exampleFunction', () => { + - it('should return 3', () => { + + it('should return 4', () => { + assert.equal(exampleFunction(), 3); + }); + }); + ``` + """.trimIndent() + val ui by lazy { ApplicationInterface(this) } + override fun renderResponse(response: String, task: SessionTask): String = """
${ + renderMarkdown( + addApplyDiffLinks( + this, + code = { + editor.document.getText(TextRange(selectionStart, selectionEnd)) + }, + response = response, + handle = { newCode: String -> + WriteCommandAction.runWriteCommandAction(editor.project) { + selectionEnd = selectionStart + newCode.length + document.replaceString(selectionStart, selectionStart + rawText.length, newCode) + } + }, + task = task, + ui = ui + ) + ) + }
""" + } + } + + + private fun openBrowserWindow(e: AnActionEvent, session: Session) { + IntellijAppManager.getApplication().executeOnPooledThread { + val server = AppServer.getServer(e.project) + val uri = server.server.uri.resolve("/#$session") + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } + } + + + companion object { + private val log = LoggerFactory.getLogger(DiffChatAction::class.java) + } +} diff --git a/src/main/kotlin/aicoder/actions/chat/GenericChatAction.kt b/src/main/kotlin/aicoder/actions/chat/GenericChatAction.kt new file mode 100644 index 00000000..c4dfe7bb --- /dev/null +++ b/src/main/kotlin/aicoder/actions/chat/GenericChatAction.kt @@ -0,0 +1,80 @@ +package aicoder.actions.chat + +import aicoder.actions.BaseAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.chat.ChatSocketManager +import org.slf4j.LoggerFactory +import java.text.SimpleDateFormat + +class GenericChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + private val systemPrompt = "" + private val userInterfacePrompt = "" + private val model by lazy { AppSettingsState.instance.smartModel.chatModel() } + + override fun handle(e: AnActionEvent) { + val project = e.project ?: return + + try { + UITools.runAsync(project, "Initializing Chat", true) { progress -> + progress.isIndeterminate = true + progress.text = "Setting up chat session..." + + val session = Session.newGlobalID() + aicoder.actions.SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + aicoder.actions.SessionProxyServer.agents[session] = ChatSocketManager( + session = session, + model = model, + initialAssistantPrompt = "", + userInterfacePrompt = userInterfacePrompt, + systemPrompt = systemPrompt, + api = api, + storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome), + applicationClass = ApplicationServer::class.java, + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + val server = AppServer.getServer(project) + + val uri = server.server.uri.resolve("/#$session") + ApplicationManager.getApplication().executeOnPooledThread { + try { + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + UITools.error(log, "Failed to open browser", e) + } + } + } + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + } + + override fun isEnabled(event: AnActionEvent) = true + + companion object { + private val log = LoggerFactory.getLogger(GenericChatAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/chat/LargeOutputChatAction.kt b/src/main/kotlin/aicoder/actions/chat/LargeOutputChatAction.kt new file mode 100644 index 00000000..9b4a47a4 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/chat/LargeOutputChatAction.kt @@ -0,0 +1,100 @@ +package aicoder.actions.chat + +import aicoder.actions.BaseAction +import aicoder.actions.LargeOutputChatSocketManager +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.actors.LargeOutputActor +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import java.text.SimpleDateFormat + +class LargeOutputChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + private val systemPrompt = """ + You are a helpful AI coding assistant. Please provide detailed, well-structured responses. + Break down complex explanations into clear sections using the ellipsis notation. + """.trimIndent() + + private val userInterfacePrompt = """ + # Enhanced Code Chat + This chat interface uses structured responses to better organize complex information. + Feel free to ask coding questions - responses will be broken down into clear sections. + """.trimIndent() + + private val model by lazy { AppSettingsState.instance.smartModel.chatModel() } + + override fun handle(e: AnActionEvent) { + val project = e.project ?: return + + try { + UITools.runAsync(project, "Initializing Enhanced Chat", true) { progress -> + progress.isIndeterminate = true + progress.text = "Setting up enhanced chat session..." + + val session = Session.newGlobalID() + val largeOutputActor = LargeOutputActor( + model = model, + temperature = 0.3, + maxIterations = 3 + ) + + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "Enhanced Chat @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + SessionProxyServer.agents[session] = LargeOutputChatSocketManager( + session = session, + model = model, + userInterfacePrompt = userInterfacePrompt, + systemPrompt = systemPrompt, + api = api, + storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome), + applicationClass = ApplicationServer::class.java, + largeOutputActor = largeOutputActor + ) + + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Enhanced Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + + val server = AppServer.getServer(project) + val uri = server.server.uri.resolve("/#$session") + + ApplicationManager.getApplication().executeOnPooledThread { + try { + BaseAction.log.info("Opening enhanced chat browser to $uri") + browse(uri) + } catch (e: Throwable) { + UITools.error(log, "Failed to open browser", e) + } + } + } + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + } + + override fun isEnabled(event: AnActionEvent) = true + + companion object { + private val log = LoggerFactory.getLogger(LargeOutputChatAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/chat/LargeOutputCodeChatAction.kt b/src/main/kotlin/aicoder/actions/chat/LargeOutputCodeChatAction.kt new file mode 100644 index 00000000..ac10d00b --- /dev/null +++ b/src/main/kotlin/aicoder/actions/chat/LargeOutputCodeChatAction.kt @@ -0,0 +1,140 @@ +package aicoder.actions.chat + +import aicoder.actions.BaseAction +import aicoder.actions.LargeOutputChatSocketManager +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.application.ApplicationManager +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.actors.LargeOutputActor +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import java.nio.file.Path +import java.text.SimpleDateFormat + +class LargeOutputCodeChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + private val model by lazy { AppSettingsState.instance.smartModel.chatModel() } + + override fun handle(e: AnActionEvent) { + val project = e.project ?: return + val root = getRoot(e) ?: return + val codeFiles = MultiCodeChatAction.getFiles( + PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(e.dataContext) ?: arrayOf(), + root + ) + + if (codeFiles.isEmpty()) { + log.warn("No code files selected") + return + } + + val codeSummary = generateCodeSummary(root, codeFiles) + + try { + UITools.runAsync(project, "Initializing Enhanced Code Chat", true) { progress -> + progress.isIndeterminate = true + progress.text = "Setting up enhanced code chat session..." + + val session = Session.newGlobalID() + + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "Code Analysis Chat @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + SessionProxyServer.agents[session] = LargeOutputChatSocketManager( + session = session, + model = model, + userInterfacePrompt = """ + # Enhanced Code Analysis Chat + Analyzing the following files: + ${codeFiles.joinToString("\n") { "* $it" }} + + This chat interface provides structured responses to help analyze and modify code. + Feel free to ask questions about the code - responses will be organized into clear sections. + """.trimIndent(), + systemPrompt = """ + You are a helpful AI coding assistant analyzing multiple code files. + Please provide detailed, well-structured responses about the code. + Break down complex explanations into clear sections using markdown headers. + When suggesting code changes, use proper diff format with + and - prefixes. + """.trimIndent() + "\n\nCode being analyzed:\n\n$codeSummary", + api = api, + storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome), + applicationClass = ApplicationServer::class.java, + largeOutputActor = LargeOutputActor( + model = model, + temperature = 0.3, + maxIterations = 3 + ) + ) + + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Enhanced Code Analysis Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + + val uri = AppServer.getServer(project).server.uri.resolve("/#$session") + ApplicationManager.getApplication().executeOnPooledThread { + try { + BaseAction.log.info("Opening enhanced code chat browser to $uri") + browse(uri) + } catch (e: Throwable) { + UITools.error(log, "Failed to open browser", e) + } + } + } + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + } + + private fun generateCodeSummary(root: Path, codeFiles: Set): String { + return codeFiles.filter { + root.resolve(it).toFile().exists() + }.joinToString("\n\n") { path -> + val code = root.resolve(path).toFile().readText(Charsets.UTF_8) + val extension = path.toString().split('.').lastOrNull() ?: "" + "# $path\n```$extension\n$code\n```" + } + } + + private fun getRoot(event: AnActionEvent): Path? { + val folder = UITools.getSelectedFolder(event) + return if (null != folder) { + folder.toFile.toPath() + } else { + getModuleRootForFile(UITools.getSelectedFile(event)?.parent?.toFile ?: return null).toPath() + } + } + + override fun isEnabled(event: AnActionEvent): Boolean { + val root = getRoot(event) ?: return false + val files = MultiCodeChatAction.getFiles( + PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext) ?: arrayOf(), + root + ) + return files.isNotEmpty() && super.isEnabled(event) + } + + companion object { + private val log = LoggerFactory.getLogger(LargeOutputCodeChatAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/chat/MultiCodeChatAction.kt b/src/main/kotlin/aicoder/actions/chat/MultiCodeChatAction.kt new file mode 100644 index 00000000..bbff7ae9 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/chat/MultiCodeChatAction.kt @@ -0,0 +1,203 @@ +package aicoder.actions.chat + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.MultiStepPatchAction +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.diff.AddApplyFileDiffLinks + +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.util.GPT4Tokenizer +import com.simiacryptus.skyenet.Retryable +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import com.simiacryptus.skyenet.util.MarkdownUtil +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import java.io.File +import java.nio.file.Path +import java.text.SimpleDateFormat +import java.util.* + +/** + * Action that enables multi-file code chat functionality. + * Allows users to select multiple files and discuss them with an AI assistant. + * Supports code modifications through patch application. + * + * @see BaseAction + */ + +class MultiCodeChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(event: AnActionEvent) { + val root = getRoot(event) ?: return + val codeFiles = Companion.getFiles(PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext) ?: arrayOf(), root).toMutableSet() + fun codeSummary() = codeFiles.filter { + root.resolve(it).toFile().exists() + }.associateWith { root.resolve(it).toFile().readText(Charsets.UTF_8) } + .entries.joinToString("\n\n") { (path, code) -> + val extension = path.toString().split('.').lastOrNull()?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ } + "# $path\n```$extension\n$code\n```" + } + try { + UITools.runAsync(event.project, "Initializing Chat", true) { progress -> + progress.isIndeterminate = true + progress.text = "Setting up chat session..." + val session = Session.newGlobalID() + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = PatchApp(root.toFile(), { codeSummary() }, codeFiles) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + val server = AppServer.getServer(event.project) + launchBrowser(server, session.toString()) + } + } catch (e: Throwable) { + UITools.error(log, "Failed to initialize chat session", e) + } + } + + private fun getRoot(event: AnActionEvent): Path? { + val folder = UITools.getSelectedFolder(event) + return if (null != folder) { + folder.toFile.toPath() + } else { + getModuleRootForFile(UITools.getSelectedFile(event)?.parent?.toFile ?: return null).toPath() + } + } + + private fun launchBrowser(server: AppServer, session: String) { + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + BaseAction.log.info("Opening browser to $uri") + BrowseUtil.browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + override fun isEnabled(event: AnActionEvent): Boolean { + val root = getRoot(event) ?: return false + val files = getFiles(PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext) ?: arrayOf(), root) + if (files.isEmpty()) return false + return super.isEnabled(event) + } + + /** Application class that handles the chat interface and code modifications */ + private inner class PatchApp( + override val root: File, + val codeSummary: () -> String, + val codeFiles: Set = setOf(), + ) : ApplicationServer( + applicationName = "Multi-file Patch Chat", + path = "/patchChat", + showMenubar = false, + ) { + override val singleInput = false + override val stickyInput = true + + private val mainActor: SimpleActor + get() = SimpleActor( + prompt = (""" + You are a helpful AI that helps people with coding. + + You will be answering questions about the following code: + + """.trimIndent() + codeSummary()).trim(), + model = AppSettingsState.instance.smartModel.chatModel() + ) + + /** + * Handles user messages in the chat interface + * + * @throws RuntimeException if API calls fail + * @throws IOException if file operations fail + */ + override fun userMessage( + session: Session, + user: User?, + userMessage: String, + ui: ApplicationInterface, + api: API + ) { + val settings = getSettings(session, user) ?: MultiStepPatchAction.AutoDevApp.Settings() + if (api is ChatClient) api.budget = settings.budget ?: 2.00 + val task = ui.newTask() + val codex = GPT4Tokenizer() + val api = (api as ChatClient).getChildClient().apply { + val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") + createFile.second?.apply { + logStreams += this.outputStream().buffered() + task.verbose("API log: $this") + } + } + task.echo(MarkdownUtil.renderMarkdown(userMessage)) + task.verbose(MarkdownUtil.renderMarkdown(codeFiles.joinToString("\n") { path -> + "* $path - ${codex.estimateTokenCount(root.resolve(path.toFile()).readText())} tokens" + })) + val toInput = { it: String -> listOf(codeSummary(), it) } + Retryable( + ui = ui, + task = task, + process = { content -> + "
" + MarkdownUtil.renderMarkdown(mainActor.answer(toInput(userMessage), api = api)) { + AddApplyFileDiffLinks.instrumentFileDiffs( + ui.socketManager!!, + root = root.toPath(), + response = it, + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + content.append("$path Updated") + } + }, + ui = ui, + api = api, + )!! + } + "
" + + }, + ) + } + } + + companion object { + private val log = LoggerFactory.getLogger(MultiCodeChatAction::class.java) + + fun getFiles( + virtualFiles: Array?, + root: Path + ): Set = virtualFiles?.flatMap { file -> + if (file.isDirectory && !file.name.startsWith(".")) { + getFiles(file.children, root) + } else { + setOf(root.relativize(file.toNioPath())) + } + }?.toSet() ?: emptySet() + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/chat/MultiDiffChatAction.kt b/src/main/kotlin/aicoder/actions/chat/MultiDiffChatAction.kt new file mode 100644 index 00000000..03cc7958 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/chat/MultiDiffChatAction.kt @@ -0,0 +1,230 @@ +package aicoder.actions.chat + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.MultiStepPatchAction.AutoDevApp.Settings +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.diff.AddApplyFileDiffLinks +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.models.ApiModel +import com.simiacryptus.jopenai.models.ApiModel.Role +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import com.simiacryptus.jopenai.util.GPT4Tokenizer +import com.simiacryptus.skyenet.Discussable +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.core.util.FileValidationUtils +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.text.SimpleDateFormat +import java.util.* +import java.util.concurrent.Semaphore +import java.util.concurrent.atomic.AtomicReference +import kotlin.io.path.relativeTo + +class MultiDiffChatAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + override fun isEnabled(event: AnActionEvent): Boolean { + if (FileValidationUtils.expandFileList( + *PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext)?.map { it.toFile }?.toTypedArray() ?: arrayOf() + ).isEmpty() + ) return false + return super.isEnabled(event) + } + + override fun handle(event: AnActionEvent) { + try { + val root = getRoot(event) ?: throw RuntimeException("No file or folder selected") + val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext) + val initialFiles = FileValidationUtils.expandFileList(*virtualFiles?.map { it.toFile }?.toTypedArray() ?: arrayOf()).map { + it.toPath().relativeTo(root) + }.toSet() + val session = Session.newGlobalID() + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = PatchApp(root.toFile(), initialFiles) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + val server = AppServer.getServer(event.project) + launchBrowser(server, session.toString()) + } catch (e: Exception) { + // Comprehensive error logging + log.error("Error in MultiDiffChatAction", e) + UITools.showErrorDialog(e.message ?: "", "Error") + } + } + + private fun getRoot(event: AnActionEvent): Path? { + val folder = UITools.getSelectedFolder(event) + return if (null != folder) { + folder.toFile.toPath() + } else { + getModuleRootForFile(UITools.getSelectedFile(event)?.parent?.toFile ?: return null).toPath() + } + } + + private fun launchBrowser(server: AppServer, session: String) { + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + inner class PatchApp( + override val root: File, + private val initialFiles: Set, + ) : ApplicationServer( + applicationName = "Multi-file Patch Chat", + path = "/patchChat", + showMenubar = false, + ) { + // Add proper logging + private val log = LoggerFactory.getLogger(PatchApp::class.java) + + override val singleInput = false + override val stickyInput = true + + // Add validation + private fun getCodeFiles(): Set { + if (!root.exists()) { + log.warn("Root directory does not exist: $root") + return emptySet() + } + return initialFiles.filter { path -> + val file = root.toPath().resolve(path).toFile() + val exists = file.exists() + if (!exists) log.warn("File does not exist: $file") + exists + }.toSet() + } + + private fun codeSummary(): String { + return getCodeFiles().associateWith { root.toPath().resolve(it).toFile().readText(Charsets.UTF_8) } + .entries.joinToString("\n\n") { (path, code) -> + val extension = + path.toString().split('.').lastOrNull()?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ } + "# $path\n```$extension\n$code\n```" + } + } + + + override fun userMessage( + session: Session, + user: User?, + userMessage: String, + ui: ApplicationInterface, + api: API + ) { + try { + fun mainActor(): SimpleActor { + return SimpleActor( + prompt = """ + You are a helpful AI that helps people with coding. + + You will be answering questions about the following code: + + """.trimIndent() + codeSummary() + AddApplyFileDiffLinks.patchEditorPrompt, + model = AppSettingsState.instance.smartModel.chatModel() + ) + } + + val settings = getSettings(session, user) ?: Settings() + if (api is ChatClient) api.budget = settings.budget ?: 2.00 + + val task = ui.newTask() + task.add("Processing request...") + + val api = (api as ChatClient).getChildClient().apply { + val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") + createFile.second?.apply { + logStreams += this.outputStream().buffered() + task.verbose("API log: $this") + } + } + val codex = GPT4Tokenizer() + task.verbose(renderMarkdown(getCodeFiles().joinToString("\n") { path -> + "* $path - ${codex.estimateTokenCount(root.resolve(path.toFile()).readText())} tokens" + })) + val toInput = { it: String -> listOf(codeSummary(), it) } + Discussable( + task = task, + userMessage = { userMessage }, + heading = renderMarkdown(userMessage), + initialResponse = { it: String -> mainActor().answer(toInput(it), api = api) }, + outputFn = { design: String -> + """
${ + renderMarkdown(design) { + AddApplyFileDiffLinks.instrumentFileDiffs( + ui.socketManager!!, + root = root.toPath(), + response = it, + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + task.complete("$path Updated") + } + }, + ui = ui, + api = api, + ) + } + }
""" + }, + ui = ui, + reviseResponse = { userMessages: List> -> + mainActor().respond(messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } + .toTypedArray()), + input = toInput(userMessage), + api = api) + }, + atomicRef = AtomicReference(), + semaphore = Semaphore(0), + ).call() + } catch (e: Exception) { + log.error("Error processing user message", e) + ui.newTask().error(ui, e) + } + } + } + + companion object { + private val log = LoggerFactory.getLogger(MultiDiffChatAction::class.java) + + } +} + +private fun Path.isBinary() = try { + this.toFile().length() > 4 * 1024 * 1024 || Files.readAllBytes(this).any { it == 0.toByte() } +} catch (e: Exception) { + false +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/dev/ApplyPatchAction.kt b/src/main/kotlin/aicoder/actions/dev/ApplyPatchAction.kt new file mode 100644 index 00000000..968b2855 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/dev/ApplyPatchAction.kt @@ -0,0 +1,85 @@ +package aicoder.actions.dev + +import aicoder.actions.BaseAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiManager +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.skyenet.core.util.IterativePatchUtil + +/** + * Action that allows applying a patch to selected files in the IDE. + */ +class ApplyPatchAction : BaseAction( + name = "Apply Patch", + description = "Applies a patch to the current file" +) { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(event: AnActionEvent) { + val project = event.project ?: return + val virtualFiles = UITools.getSelectedFiles(event) ?: return + + // Prompt user to input patch content + val patchContent = Messages.showMultilineInputDialog( + project, + "Enter the patch content:", + "Input Patch", + "", + null, + null + ) ?: return + if (patchContent.trim().isEmpty()) { + Messages.showErrorDialog(project, "Patch content cannot be empty", "Invalid Patch") + return + } + + virtualFiles.forEach { virtualFile -> + try { + applyPatch(virtualFile, patchContent, project) + } catch (e: Exception) { + Messages.showErrorDialog( + project, + "Failed to apply patch to ${virtualFile.name}: ${e.message}", + "Patch Application Error" + ) + } + } + } + + /** + * Applies the given patch content to a file. + * + * @param file The virtual file to patch + * @param patchContent The content of the patch to apply + * @param project The current project + */ + + private fun applyPatch(file: VirtualFile, patchContent: String, project: com.intellij.openapi.project.Project) { + WriteCommandAction.runWriteCommandAction(project) { + val psiFile = PsiManager.getInstance(project).findFile(file) ?: return@runWriteCommandAction + val newContent = IterativePatchUtil.applyPatch(psiFile.text, patchContent) + if (newContent == psiFile.text) { + Messages.showWarningDialog(project, "Patch made no changes to ${file.name}", "No Changes") + return@runWriteCommandAction + } + psiFile.virtualFile.setBinaryContent(newContent.toByteArray()) + } + } + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val selectedFiles = UITools.getSelectedFiles(event) + when { + null == selectedFiles -> return false + selectedFiles.size == 0 -> return false + selectedFiles.size > 1 -> return false + selectedFiles.first().isDirectory -> return false + else -> return true + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/dev/LineFilterChatAction.kt b/src/main/kotlin/aicoder/actions/dev/LineFilterChatAction.kt new file mode 100644 index 00000000..90de52eb --- /dev/null +++ b/src/main/kotlin/aicoder/actions/dev/LineFilterChatAction.kt @@ -0,0 +1,144 @@ +package aicoder.actions.dev + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.chat.ChatSocketManager +import com.simiacryptus.skyenet.webui.session.SessionTask +import org.slf4j.LoggerFactory +import java.text.SimpleDateFormat + +class LineFilterChatAction : BaseAction() { + private lateinit var lines: List + + data class ChatConfig( + val language: String, + val filename: String, + val code: String, + val lines: Array + ) + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + val path = "/codeChat" + + override fun handle(e: AnActionEvent) { + val editor = e.getData(CommonDataKeys.EDITOR) ?: return + val session = Session.newGlobalID() + val config = getConfig(e, editor) ?: run { + UITools.error(log, "Error", Exception("Could not get required configuration")) + return + } + try { + setupChatManager(session, config) + openBrowser(e.project, session) + } catch (ex: Throwable) { + log.error("Error setting up chat", ex) + UITools.error(log, "Error", ex) + } + } + + private fun getConfig(e: AnActionEvent, editor: Editor): ChatConfig? { + return try { + val language = ComputerLanguage.getComputerLanguage(e)?.name ?: return null + val filename = FileDocumentManager.getInstance().getFile(editor.document)?.name ?: return null + val code = editor.caretModel.primaryCaret.selectedText ?: editor.document.text + val lines = code.split("\n").toTypedArray() + ChatConfig(language, filename, code, lines) + } catch (e: Exception) { + log.error("Error getting configuration", e) + null + } + } + + private fun setupChatManager(session: Session, config: ChatConfig) { + val codelines = config.lines.withIndex().joinToString("\n") { (i, line) -> + "${i.toString().padStart(3, '0')} $line" + } + val userPrompt = buildString { + append("# `${config.filename}`\n\n") + append("```${config.language}\n") + append(config.code) + append("\n```") + } + val systemPrompt = buildString { + append("You are a helpful AI that helps people with coding.\n\n") + append("You will be answering questions about the following code located in `${config.filename}`:\n\n") + append("```${config.language}\n") + append(codelines) + append("\n```\n\n") + append("Responses may use markdown formatting. Lines from the prompt can be included ") + append("by using the line number in a response line (e.g. `\\nLINE\\n`).\n\n") + append("For example:\n\n") + append("```text\n") + append("001\n## Injected subtitle\n\n025\n026\n\n013\n014\n") + append("```") + } + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.agents[session] = object : ChatSocketManager( + session = session, + model = AppSettingsState.instance.smartModel.chatModel(), + userInterfacePrompt = userPrompt, + systemPrompt = systemPrompt, + api = api, + applicationClass = ApplicationServer::class.java, + storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) + ) { + override fun canWrite(user: User?): Boolean = true + override fun renderResponse(response: String, task: SessionTask): String { + return com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown(response.split("\n").joinToString("\n") { + when { + // Is numeric, use line if in range + it.toIntOrNull()?.let { i -> lines.indices.contains(i) } == true -> lines[it.toInt()] + // Otherwise, use response + else -> it + } + } + ) + } + } + } + + private fun openBrowser(project: Project?, session: Session) { + + val server = AppServer.getServer(project) + + ApplicationManager.getApplication().executeOnPooledThread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } catch (ex: Throwable) { + log.warn("Error opening browser", ex) + } + } + } + + override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.devActions + + companion object { + private val log = LoggerFactory.getLogger(LineFilterChatAction::class.java) + + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/dev/PrintTreeAction.kt b/src/main/kotlin/aicoder/actions/dev/PrintTreeAction.kt new file mode 100644 index 00000000..aa216d59 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/dev/PrintTreeAction.kt @@ -0,0 +1,55 @@ +package aicoder.actions.dev + +import aicoder.actions.BaseAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.aicoder.util.psi.PsiUtil +import org.slf4j.LoggerFactory + +/** + * The PrintTreeAction class is an IntelliJ action that enables developers to print the tree structure of a PsiFile. + * To use this action, first make sure that the "devActions" setting is enabled. + * Then, open the file you want to print the tree structure of. + * Finally, select the "PrintTreeAction" action from the editor context menu. + * This will print the tree structure of the file to the log. + * + * @property log Logger instance for this class + * @see BaseAction + * @see PsiUtil + */ +class PrintTreeAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + val project = e.project ?: return + UITools.runAsync(project, "Analyzing Code Structure", true) { progress -> + try { + progress.isIndeterminate = true + progress.text = "Generating PSI tree structure..." + ApplicationManager.getApplication().executeOnPooledThread { + val psiEntity = PsiUtil.getLargestContainedEntity(e) + if (psiEntity != null) { + log.info(PsiUtil.printTree(psiEntity)) + } else { + log.warn("No PSI entity found in current context") + } + } + } catch (ex: Throwable) { + UITools.error(log, "Failed to print PSI tree", ex) + } + } + } + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + if (!AppSettingsState.instance.devActions) return false + return PsiUtil.getLargestContainedEntity(event) != null + } + + companion object { + private val log = LoggerFactory.getLogger(PrintTreeAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/editor/CustomEditAction.kt b/src/main/kotlin/aicoder/actions/editor/CustomEditAction.kt new file mode 100644 index 00000000..fb92832b --- /dev/null +++ b/src/main/kotlin/aicoder/actions/editor/CustomEditAction.kt @@ -0,0 +1,96 @@ +package aicoder.actions.editor + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy +import javax.swing.JOptionPane + +/** + * Action that allows custom editing of code selections using AI. + * Supports multiple languages and provides custom edit instructions. + */ +open class CustomEditAction : SelectionAction(requiresSelection = true) { + private val log = Logger.getInstance(CustomEditAction::class.java) + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + interface VirtualAPI { + fun editCode( + code: String, + operation: String, + computerLanguage: String, + humanLanguage: String + ): EditedText + + data class EditedText( + var code: String? = null, + var language: String? = null + ) + } + + val proxy: VirtualAPI + get() { + val chatProxy = ChatProxy( + clazz = VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + ) + chatProxy.addExample( + VirtualAPI.EditedText( + """ + // Print Hello, World! to the console + println("Hello, World!") + """.trimIndent(), + "java" + ) + ) { + it.editCode( + """println("Hello, World!")""", + "Add code comments", + "java", + "English" + ) + } + return chatProxy.create() + } + + override fun getConfig(project: Project?): String? { + return UITools.showInputDialog( + null, + "Enter edit instruction:", + "Edit Code", + JOptionPane.QUESTION_MESSAGE + ) as String? + } + + override fun processSelection(state: SelectionState, config: String?, progress: ProgressIndicator): String { + if (config.isNullOrBlank()) return state.selectedText ?: "" + return try { + progress.isIndeterminate = true + progress.text = "Applying edit: $config" + val settings = AppSettingsState.instance + val outputHumanLanguage = settings.humanLanguage + settings.getRecentCommands("customEdits").addInstructionToHistory(config) + val result = proxy.editCode( + state.selectedText ?: "", + config, + state.language?.name ?: state.editor?.virtualFile?.extension ?: "unknown", + outputHumanLanguage + ) + result.code ?: state.selectedText ?: "" + } catch (e: Exception) { + log.error("Failed to process edit", e) + UITools.showErrorDialog( + "Failed to process edit: ${e.message}", + "Edit Error" + ) + state.selectedText ?: "" + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/editor/DescribeAction.kt b/src/main/kotlin/aicoder/actions/editor/DescribeAction.kt new file mode 100644 index 00000000..76b6be8d --- /dev/null +++ b/src/main/kotlin/aicoder/actions/editor/DescribeAction.kt @@ -0,0 +1,104 @@ +package aicoder.actions.editor + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.aicoder.util.IndentedText +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy + +// ... keep existing imports + +class DescribeAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + private val log = Logger.getInstance(DescribeAction::class.java) + + data class SelectionState( + val language: ComputerLanguage?, + val selectedText: String?, + val indent: String? + ) + + protected fun getState(event: AnActionEvent): SelectionState? { + val editor: Editor = event.getData(CommonDataKeys.EDITOR) ?: return null + val caret = editor.caretModel.primaryCaret + val file: VirtualFile? = event.getData(CommonDataKeys.VIRTUAL_FILE) + return SelectionState( + language = file?.let { ComputerLanguage.findByExtension(it.extension ?: "") }, + selectedText = if (caret.hasSelection()) editor.document.getText(TextRange(caret.selectionStart, caret.selectionEnd)) else null, + indent = UITools.getIndent(caret).toString() + ) + } + + + interface DescribeAction_VirtualAPI { + fun describeCode( + code: String, + computerLanguage: String, + humanLanguage: String + ): DescribeAction_ConvertedText + + class DescribeAction_ConvertedText { + var text: String? = null + var language: String? = null + } + } + + private val proxy: DescribeAction_VirtualAPI + get() = ChatProxy( + clazz = DescribeAction_VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ).create() + + override fun getConfig(project: Project?): String { + // No configuration needed for this action + return "" + } + + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val state = getState(event) + return state?.selectedText?.isNotBlank() == true + } + + override fun processSelection(state: SelectionAction.SelectionState, config: String?, progress: ProgressIndicator): String { + try { + val description = proxy.describeCode( + IndentedText.fromString(state.selectedText).textBlock.toString().trim(), + state.language?.name ?: state.editor?.virtualFile?.extension ?: "", + AppSettingsState.instance.humanLanguage + ).text ?: throw IllegalStateException("Failed to generate description") + val wrapping = com.simiacryptus.aicoder.util.StringUtil.lineWrapping(description.trim(), 120) + val numberOfLines = wrapping.trim().split("\n").reversed().dropWhile { it.isEmpty() }.size + val commentStyle = if (numberOfLines == 1) { + state.language?.lineComment + } else { + state.language?.blockComment + } + return buildString { + append(state.indent) + append(commentStyle?.fromString(wrapping)?.withIndent(state.indent!!) ?: wrapping) + append("\n") + append(state.indent) + append(state.selectedText) + } + } catch (e: Exception) { + log.error("Failed to describe code", e) + throw e + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/editor/PasteAction.kt b/src/main/kotlin/aicoder/actions/editor/PasteAction.kt new file mode 100644 index 00000000..17c3aee8 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/editor/PasteAction.kt @@ -0,0 +1,194 @@ +package aicoder.actions.editor + +// ... keep existing imports +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.awt.Toolkit +import java.awt.datatransfer.DataFlavor.* + +/** + * Base class for paste actions that convert clipboard content to appropriate code format + * Supports both text and HTML clipboard content with automatic language detection + */ +abstract class PasteActionBase(private val model: (AppSettingsState) -> ChatModel) : SelectionAction(false) { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + /** + * API interface for code conversion + */ + interface VirtualAPI { + fun convert(text: String, from_language: String, to_language: String): ConvertedText + + /** + * Response class containing converted code + */ + + class ConvertedText { + var code: String? = null + var language: String? = null + } + } + + companion object { + private val log: Logger = LoggerFactory.getLogger(PasteActionBase::class.java) + fun scrubHtml(str: String, maxLength: Int = 100 * 1024): String { + val document: Document = Jsoup.parse(str) + // Remove unnecessary elements, attributes, and optimize the document + document.apply { + fun qTry(block: () -> Unit) { + return try { + block() + } catch (e: Exception) { + log.error("Error in scrubHtml", e) + } + } + if ((document.body()?.html()?.length ?: 0) > maxLength) return document.body()?.html()?.substring(0, maxLength) ?: "" + select("script, style, link, meta, iframe, noscript").remove() // Remove unnecessary and potentially harmful tags + outputSettings().prettyPrint(false) // Disable pretty printing for compact output + if ((document.body()?.html()?.length ?: 0) > maxLength) return document.body()?.html()?.substring(0, maxLength) ?: "" + // Remove comments + qTry { select("*").forEach { it.childNodes().removeAll { node -> node.nodeName() == "#comment" } } } + if (document.body().html().length > maxLength) return@apply + // Remove data-* attributes + qTry { select("*[data-*]").forEach { it.attributes().removeAll { attr -> attr.key.startsWith("data-") } } } + if (document.body().html().length > maxLength) return@apply + qTry { + select("*").forEach { element -> + val importantAttributes = setOf("href", "src", "alt", "title", "width", "height", "style", "class", "id", "name") + element.attributes().removeAll { it.key !in importantAttributes } + } + } + if (document.body().html().length > maxLength) return@apply + // Remove empty elements + qTry { + select("*").forEach { element -> + if (element.childNodes().isEmpty() && element.attributes().isEmpty()) { + element.remove() + } + } + } + if (document.body().html().length > maxLength) return@apply + // Unwrap single-child elements with no attributes + qTry { + select("*").forEach { element -> + if (element.childNodes().size == 1 && element.childNodes()[0].nodeName() == "#text" && element.attributes().isEmpty()) { + element.unwrap() + } + } + } + if (document.body().html().length > maxLength) return@apply + // Convert relative URLs to absolute + qTry { + select("[href],[src]").forEach { element -> + element.attr("href").let { href -> element.attr("href", href.makeAbsolute()) } + element.attr("src").let { src -> element.attr("src", src.makeAbsolute()) } + } + } + if (document.body().html().length > maxLength) return@apply + // Remove empty attributes + qTry { + select("*").forEach { element -> + element.attributes().removeAll { it.value.isBlank() } + } + } + } + + // Truncate if necessary + val result = document.body().html() + return if (result.length > maxLength) { + result.substring(0, maxLength) + } else { + result + } + } + + fun getClipboard(): Any? { + try { + val toolkit = Toolkit.getDefaultToolkit() + val systemClipboard = toolkit.systemClipboard + return systemClipboard.getContents(null)?.let { contents -> + return when { + contents.isDataFlavorSupported(selectionHtmlFlavor) -> contents.getTransferData(selectionHtmlFlavor).toString().trim().let { scrubHtml(it) } + contents.isDataFlavorSupported(fragmentHtmlFlavor) -> contents.getTransferData(fragmentHtmlFlavor).toString().trim().let { scrubHtml(it) } + contents.isDataFlavorSupported(allHtmlFlavor) -> contents.getTransferData(allHtmlFlavor).toString().trim().let { scrubHtml(it) } + contents.isDataFlavorSupported(stringFlavor) -> contents.getTransferData(stringFlavor) + contents.isDataFlavorSupported(getTextPlainUnicodeFlavor()) -> contents.getTransferData(getTextPlainUnicodeFlavor()) + else -> null + } + } + } catch (e: Exception) { + log.error("Failed to access clipboard", e) + return null + } + } + + fun hasClipboard() = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)?.let { contents -> + return when { + contents.isDataFlavorSupported(stringFlavor) -> true + contents.isDataFlavorSupported(getTextPlainUnicodeFlavor()) -> true + else -> false + } + } ?: false + + fun converter(chatClient: ChatClient, chatModel: ChatModel, temp: Double) = ChatProxy(VirtualAPI::class.java, chatClient, chatModel, temp).create() + } + + override fun getConfig(project: Project?): String { + return "" + } + + + override fun processSelection(state: SelectionState, config: String?, progress: ProgressIndicator): String { + val progress: ProgressIndicator? = state.progress + progress?.text = "Reading clipboard content..." + val clipboardContent = getClipboard() ?: return "" + val text = clipboardContent.toString().trim() + progress?.text = "Converting code format..." + val converter = converter(api, model(AppSettingsState.instance), AppSettingsState.instance.temperature) + return converter.convert(text, "autodetect", state.language?.name ?: state.editor?.virtualFile?.extension ?: "").code ?: "" + } + + override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { + return true + } + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!hasClipboard()) return false + return super.isEnabled(event) + } + +} + +private fun String.makeAbsolute(): String { + return if (startsWith("http://") || startsWith("https://") || startsWith("//")) { + this + } else { + "https://$this" + } +} + +class SmartPasteAction : PasteActionBase({ it.smartModel.chatModel() }) + +/** + * Fast paste action using faster but simpler model + */ +class FastPasteAction : PasteActionBase({ it.fastModel.chatModel() }) { + companion object { + private val log = LoggerFactory.getLogger(FastPasteAction::class.java) + } + + protected var progress: ProgressIndicator? = null +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/editor/RecentCodeEditsAction.kt b/src/main/kotlin/aicoder/actions/editor/RecentCodeEditsAction.kt new file mode 100644 index 00000000..0892c779 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/editor/RecentCodeEditsAction.kt @@ -0,0 +1,46 @@ +package aicoder.actions.editor + +import com.intellij.openapi.actionSystem.ActionGroup +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.aicoder.util.UITools + +class RecentCodeEditsAction : ActionGroup() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun update(e: AnActionEvent) { + e.presentation.isEnabledAndVisible = isEnabled(e) + super.update(e) + } + + override fun getChildren(e: AnActionEvent?): Array { + if (e == null) return emptyArray() + val children = mutableListOf() + for (instruction in AppSettingsState.instance.getRecentCommands("customEdits").getMostRecent(10)) { + val id = children.size + 1 + val text = if (id < 10) "_$id: $instruction" else "$id: $instruction" + val element = object : CustomEditAction() { + override fun getConfig(project: Project?): String { + return instruction + } + } + element.templatePresentation.text = text + element.templatePresentation.description = instruction + element.templatePresentation.icon = null + children.add(element) + } + return children.toTypedArray() + } + + companion object { + fun isEnabled(e: AnActionEvent): Boolean { + if (!UITools.hasSelection(e)) return false + val computerLanguage = ComputerLanguage.getComputerLanguage(e) + return computerLanguage != ComputerLanguage.Text + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/editor/RedoLast.kt b/src/main/kotlin/aicoder/actions/editor/RedoLast.kt new file mode 100644 index 00000000..a35827fb --- /dev/null +++ b/src/main/kotlin/aicoder/actions/editor/RedoLast.kt @@ -0,0 +1,27 @@ +package aicoder.actions.editor + +import aicoder.actions.BaseAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.simiacryptus.aicoder.util.UITools.retry + +/** + * The RedoLast action is an IntelliJ action that allows users to redo the last AI Coder action they performed in the editor. + * To use this action, open the editor and select the RedoLast action from the editor context menu. + * This will redo the last action that was performed in the editor. + */ +class RedoLast : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + val editor = e.getData(CommonDataKeys.EDITOR) ?: return + retry[editor.document]?.run() + } + + override fun isEnabled(event: AnActionEvent): Boolean { + val editor = event.getData(CommonDataKeys.EDITOR) ?: return false + return retry[editor.document] != null + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/find/FindResultsChatAction.kt b/src/main/kotlin/aicoder/actions/find/FindResultsChatAction.kt new file mode 100644 index 00000000..7d3b3cd9 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/find/FindResultsChatAction.kt @@ -0,0 +1,203 @@ +package aicoder.actions.find + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.MultiStepPatchAction +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.findPsiFile +import com.intellij.psi.PsiDocumentManager +import com.intellij.usages.Usage +import com.intellij.usages.UsageView +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.Retryable +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import java.io.File +import java.text.SimpleDateFormat +import java.util.* +import javax.swing.Icon + +class FindResultsChatAction( + name: String? = "Chat About Find Results", + description: String? = "Start a code chat about find results", + icon: Icon? = null +) : BaseAction(name, description, icon) { + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(event: AnActionEvent) { + val project = event.project ?: return + val usageView = event.getData(UsageView.USAGE_VIEW_KEY) ?: return + val usages = usageView.usages.toTypedArray() + + if (usages.isEmpty()) { + UITools.showWarning(project, "No find results selected for chat") + return + } + + try { + val root = getModuleRootForFile( + UITools.getSelectedFile(event)?.parent?.toFile + ?: throw RuntimeException("No file selected") + ) + + val session = Session.newGlobalID() + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + val fileListMap = usages.groupBy { getFile(it) } + SessionProxyServer.chats[session] = ChatApp( + root = root, + project = project, + usages = fileListMap + ) + + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Find Results Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + + val server = AppServer.getServer(event.project) + UITools.runAsync(event.project, "Opening Browser", true) { progress -> + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + val message = "Failed to open browser: ${e.message}" + log.error(message, e) + UITools.showErrorDialog(message, "Error") + } + } + } catch (ex: Exception) { + UITools.error(log, "Error starting chat", ex) + } + } + + private fun getFile(it: Usage) = it.location?.editor?.file + + override fun isEnabled(event: AnActionEvent): Boolean { + val usageView = event.getData(UsageView.USAGE_VIEW_KEY) + return usageView != null && usageView.usages.isNotEmpty() + } + + inner class ChatApp( + override val root: File, + val project: Project, + val usages: Map> + ) : ApplicationServer( + applicationName = "Find Results Chat", + path = "/findChat", + showMenubar = false, + ) { + override val singleInput = false + override val stickyInput = true + private fun formatLine(index: Int, line: String, isFocused: Boolean) = when { + isFocused -> "/* L$index */ $line /* <<< */" + else -> "/* L$index */ $line" + } + + private fun getFilteredLines(project: Project, file: VirtualFile, usages: List): String? { + val document = PsiDocumentManager.getInstance(project) + .getDocument(file.findPsiFile(project) ?: return null) ?: return null + return document.text.lines().mapIndexed { index: Int, line: String -> + val lineStart = document.getLineStartOffset(index) + val lineEnd = document.getLineEndOffset(index) + val intersectingUsages = usages.filter { usage -> + val startOffset = usage.navigationOffset + val endOffset = startOffset + 1 + when { + startOffset >= lineEnd -> false + endOffset <= lineStart -> false + else -> true + } + } + when { + intersectingUsages.isNotEmpty() -> formatLine(index, line, true) + else -> "..." + } + }.joinToString("\n").replace("(?:\\.\\.\\.\n){2,}".toRegex(), "...\n") + } + + + private fun getCodeContext(): String { + return usages.entries.joinToString("\n\n") { (file, usages) -> + file ?: return@joinToString "" + + val document = PsiDocumentManager.getInstance(project).getDocument( + file.findPsiFile(project) ?: return@joinToString "" + ) ?: return@joinToString "" + + val usageLocations = usages.joinToString("\n") { usage -> + val lineNumber = document.getLineNumber(usage.navigationOffset) + "* Line ${lineNumber + 1}: ${usage.presentation.plainText}" + } + "\n## ${file.name}\nUsage locations:\n$usageLocations\n```${file.extension}\n${getFilteredLines(project, file, usages)}\n```" + } + } + + override fun userMessage( + session: Session, + user: User?, + userMessage: String, + ui: ApplicationInterface, + api: API + ) { + val settings = getSettings(session, user) ?: MultiStepPatchAction.AutoDevApp.Settings() + if (api is ChatClient) api.budget = settings.budget ?: 2.00 + + val task = ui.newTask() + val api = (api as ChatClient).getChildClient().apply { + val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") + createFile.second?.apply { + logStreams += this.outputStream().buffered() + task.verbose("API log: $this") + } + } + + task.echo(renderMarkdown(userMessage)) + + task.verbose(renderMarkdown(getCodeContext())) + + Retryable( + ui = ui, + task = task, + process = { content -> + "
" + renderMarkdown( + SimpleActor( + prompt = """ + You are a helpful AI that helps people understand code. + You will be answering questions about code with the following find results: + + """.trimIndent() + getCodeContext(), + model = AppSettingsState.instance.smartModel.chatModel() + ).answer(listOf(userMessage), api = api) + ) + "
" + } + ) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/find/FindResultsModificationAction.kt b/src/main/kotlin/aicoder/actions/find/FindResultsModificationAction.kt new file mode 100644 index 00000000..702b210b --- /dev/null +++ b/src/main/kotlin/aicoder/actions/find/FindResultsModificationAction.kt @@ -0,0 +1,268 @@ +package aicoder.actions + +import aicoder.actions.agent.toFile +import aicoder.actions.find.FindResultsModificationDialog +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.findPsiFile +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiFile +import com.intellij.psi.util.endOffset +import com.intellij.psi.util.startOffset +import com.intellij.usages.Usage +import com.intellij.usages.UsageInfo2UsageAdapter +import com.intellij.usages.UsageView +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.aicoder.util.psi.PsiUtil +import com.simiacryptus.diff.AddApplyFileDiffLinks + +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.TabbedDisplay +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager +import com.simiacryptus.skyenet.webui.session.SocketManager +import java.io.File +import java.nio.file.Path +import java.text.SimpleDateFormat +import java.util.* +import javax.swing.Icon + +class FindResultsModificationAction( + name: String? = "Modify Find Results", + description: String? = "Modify files based on find results", + icon: Icon? = null +) : BaseAction(name, description, icon) { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(event: AnActionEvent) { + val folder = UITools.getSelectedFolder(event) + val root: Path = if (null != folder) { + folder.toFile.toPath() + } else { + getModuleRootForFile( + UITools.getSelectedFile(event)?.parent?.toFile + ?: throw RuntimeException("No file or folder selected") + ).toPath() + } + val project = event.project ?: return + val usageView = event.getData(UsageView.USAGE_VIEW_KEY) ?: return + val usages = usageView.usages.toTypedArray() + if (usages.isEmpty()) { + UITools.showWarning(project, "No find results selected for modification") + return + } + val modificationParams = showModificationDialog(project, *usages) ?: return + try { + val session = Session.newGlobalID() + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + val fileListMap = usages.groupBy { getFile(it) } + SessionProxyServer.chats[session] = PatchApp( + root = root.toFile(), + modificationParams = modificationParams, + project = event.project ?: return, + usages = fileListMap + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + val server = AppServer.getServer(event.project) + UITools.runAsync(event.project, "Opening Browser", true) { progress -> + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + val message = "Failed to open browser: ${e.message}" + log.error(message, e) + UITools.showErrorDialog(message, "Error") + } + } + } catch (ex: Exception) { + UITools.error(log, "Error modifying files", ex) + } + } + + private fun getFile(it: Usage) = when { + it is UsageInfo2UsageAdapter -> { + it.file + } + + else -> { + it.location?.editor?.file + } + } + + inner class PatchApp( + override val root: File, + val modificationParams: ModificationParams, + val project: Project, + val usages: Map>, + ) : ApplicationServer( + applicationName = "Multi-file Patch Chat", + path = "/patchChat", + showMenubar = false, + ) { + override val singleInput = true + override val stickyInput = false + + override fun newSession(user: User?, session: Session): SocketManager { + val socketManager = super.newSession(user, session) + val ui = (socketManager as ApplicationSocketManager).applicationInterface + val task = ui.newTask() + val api = api.getChildClient().apply { + val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") + createFile.second?.apply { + logStreams += this.outputStream().buffered() + task.verbose("API log: $this") + } + } + val tabs = TabbedDisplay(task) + usages.entries.map { (file, usages) -> + val task = ui.newTask(false) + tabs[file?.name ?: "Unknown"] = task.placeholder + lateinit var fileListingMarkdown: String + lateinit var prompt: String + ApplicationManager.getApplication().runReadAction { + file ?: return@runReadAction + fileListingMarkdown = "## ${file.name}\n\n```${file.extension}\n${getFilteredLines(project, file, usages)}\n```\n" + task.add(renderMarkdown(fileListingMarkdown)) + prompt = """ + You are a code modification assistant. You will receive code files and locations where changes are needed. + Your task is to suggest appropriate modifications based on the replacement text provided. + Usage locations: + """.trimIndent() + usages.joinToString("\n") { "* `${it.presentation.plainText}`" } + + "\n\nRequested modification: " + modificationParams.replacementText + "\n\n" + AddApplyFileDiffLinks.patchEditorPrompt + } + ui.socketManager!!.pool.submit { + val api = api.getChildClient().apply { + val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") + createFile.second?.apply { + logStreams += this.outputStream().buffered() + task.verbose("API log: $this") + } + } + val response = SimpleActor( + prompt = prompt, + model = AppSettingsState.instance.smartModel.chatModel() + ).answer( + listOf( + fileListingMarkdown + ), api + ).replace(Regex("""/\* L\d+ \*/"""), "") + .replace(Regex("""/\* <<< \*/"""), "") + AddApplyFileDiffLinks.instrumentFileDiffs( + ui.socketManager!!, + root = root.toPath(), + response = response, + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + task.complete("Updated $path") + } + }, + ui = ui, + api = api, + shouldAutoApply = { modificationParams.autoApply }, + defaultFile = file?.toFile?.path + )?.apply { + task.complete(renderMarkdown(this)) + } + } + }.toTypedArray().forEach { it.get() } + return socketManager + } + + } + + private fun getSmallestContainingEntity(psiRoot: PsiFile?, usage: Usage) = + PsiUtil.getSmallestContainingEntity( + element = psiRoot!!, + selectionStart = usage.navigationOffset, + selectionEnd = usage.presentation.plainText.length + usage.navigationOffset - 1 + ) + + private fun formatLine(index: Int, line: String, isFocused: Boolean) = when { + isFocused -> "/* L$index */ $line /* <<< */" + else -> "/* L$index */ $line" + } + +private fun getFilteredLines(project: Project, file: VirtualFile, usages: List): String? { + val document = + PsiDocumentManager.getInstance(project).getDocument(file.findPsiFile(project) ?: return null) ?: return null + val psiRoot: PsiFile? = file.findPsiFile(project) + val byContainer = usages.groupBy { getSmallestContainingEntity(psiRoot, it) }.entries.sortedBy { it.key?.textRange?.startOffset }.toTypedArray() + val filteredLines = document.text.lines().mapIndexed { index: Int, line: String -> + val lineStart = document.getLineStartOffset(index) + val lineEnd = document.getLineEndOffset(index) + val containers = byContainer.map { it.key }.filter { psiElement -> + psiElement ?: return@filter false + val textRange = psiElement.textRange + val startOffset = textRange.startOffset + val endOffset = textRange.endOffset + when { + startOffset >= lineEnd -> false + endOffset <= lineStart -> false + else -> true + } + } + val intersectingUsages = usages.filter { usage -> + //val plainText = usage.presentation.plainText.trim() + val startOffset = usage.navigationOffset + val endOffset = startOffset + 1 // (plainText.length-1) + when { + startOffset >= lineEnd -> false + endOffset <= lineStart -> false + else -> true + } + } + when { + intersectingUsages.isNotEmpty() -> formatLine(index, line, true) + containers.isNotEmpty() -> formatLine(index, line, false) + else -> "..." + } + }.joinToString("\n").replace("(?:\\.\\.\\.\n){2,}".toRegex(), "...\n") + return filteredLines + } + + override fun isEnabled(event: AnActionEvent): Boolean { + val usageView = event.getData(UsageView.USAGE_VIEW_KEY) + return usageView != null && usageView.usages.isNotEmpty() + } + + private fun showModificationDialog(project: Project, vararg usages: Usage): ModificationParams? { + val dialog = FindResultsModificationDialog(project, usages.size) + val config = dialog.showAndGetConfig() + return if (config != null) { + ModificationParams( + replacementText = config.replacementText ?: "", + autoApply = config.autoApply + ) + } else null + } + + data class ModificationParams( + val replacementText: String, + val autoApply: Boolean + ) + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/find/FindResultsModificationDialog.kt b/src/main/kotlin/aicoder/actions/find/FindResultsModificationDialog.kt new file mode 100644 index 00000000..6d2eec3b --- /dev/null +++ b/src/main/kotlin/aicoder/actions/find/FindResultsModificationDialog.kt @@ -0,0 +1,71 @@ +package aicoder.actions.find + +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.ui.ValidationInfo +import com.intellij.ui.dsl.builder.* +import javax.swing.JComponent + +class FindResultsModificationDialog( + project: Project, + matchCount: Int +) : DialogWrapper(project) { + + private var replacementText = "Please modify this code to: " + private var autoApply = false + + init { + title = "AI-Based Find Results Modification" + setOKButtonText("Modify Code") + init() + } + + override fun createCenterPanel(): JComponent { + return panel { + row("Modification Instructions:") { + textArea() + .bindText({ replacementText }, { replacementText = it }) + .rows(5) + .align(Align.FILL) + .comment("Enter instructions for how you want the code to be modified") + .focused() + .apply { + component.lineWrap = true + component.wrapStyleWord = true + component.selectAll() + } + }.resizableRow() + row { + checkBox("Auto-apply changes") + .bindSelected({ autoApply }, { autoApply = it }) + .comment("Automatically apply changes without manual confirmation") + } + } + } + + override fun doValidate(): ValidationInfo? { + if (replacementText.isBlank()) { + return ValidationInfo("Please enter instructions for code modification") + } + if (replacementText.length < 10) { + return ValidationInfo("Please provide more detailed instructions") + } + return null + } + + data class ConfigData( + val replacementText: String?, + val autoApply: Boolean + ) + + fun showAndGetConfig(): ConfigData? { + if (showAndGet()) { + return ConfigData( + replacementText = replacementText, + autoApply = autoApply + ) + } + return null + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/generate/CreateFileFromDescriptionAction.kt b/src/main/kotlin/aicoder/actions/generate/CreateFileFromDescriptionAction.kt new file mode 100644 index 00000000..73de06aa --- /dev/null +++ b/src/main/kotlin/aicoder/actions/generate/CreateFileFromDescriptionAction.kt @@ -0,0 +1,165 @@ +package aicoder.actions.generate + +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.config.Name +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.ApiModel.* +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import java.io.File +import javax.swing.JTextArea + +class CreateFileFromDescriptionAction : aicoder.actions.FileContextAction(false, true) { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + private val log = Logger.getInstance(CreateFileFromDescriptionAction::class.java) + + companion object { + private const val DEFAULT_DIRECTIVE = "Create a new file" + private const val FILE_PATH_REGEX = """File(?:name)?: ['`"]?([^'`"]+)['`"]?""" + } + + class ProjectFile(var path: String = "", var code: String = "") + + class SettingsUI { + @Name("Directive") + val directive: JTextArea = JTextArea( + DEFAULT_DIRECTIVE, + 3, + 120 + ) + } + + class Settings( + var directive: String = "", + val project: Project? = null + ) + + override fun getConfig(project: Project?, e: AnActionEvent): Settings { + val userSettings = UITools.showDialog( + project, + SettingsUI::class.java, + Settings::class.java, + "Create File From Description" + ) + return Settings(userSettings.directive, project) + } + + override fun processSelection( + state: SelectionState, + config: Settings?, + progress: ProgressIndicator + ): Array { + progress.isIndeterminate = false + progress.text = "Generating file from description..." + return try { + processSelectionInternal(state, config, progress) + } catch (e: Exception) { + log.error("Failed to create file from description", e) + UITools.showErrorDialog( + "Failed to create file: ${e.message}", + "Error" + ) + emptyArray() + } + } + + private fun processSelectionInternal( + state: SelectionState, + config: Settings?, + progress: ProgressIndicator + ): Array { + require(state.projectRoot.exists()) { "Project root directory does not exist" } + require(state.selectedFile.exists()) { "Selected file does not exist" } + + val projectRoot = state.projectRoot.toPath() + val inputPath = projectRoot.relativize(state.selectedFile.toPath()).toString() + val pathSegments = inputPath.split("/").toList() + val updirSegments = pathSegments.takeWhile { it == ".." } + val moduleRoot = projectRoot.resolve(pathSegments.take(updirSegments.size * 2).joinToString("/")) + val filePath = pathSegments.drop(updirSegments.size * 2).joinToString("/") + progress.text = "Generating file content..." + progress.fraction = 0.3 + + val generatedFile = generateFile(filePath, config?.directive ?: DEFAULT_DIRECTIVE) + + var path = generatedFile.path + var outputPath = moduleRoot.resolve(path) + if (outputPath.toFile().exists()) { + val extension = path.substringAfterLast(".") + val name = path.substringBeforeLast(".") + val fileIndex = (1..Int.MAX_VALUE).find { + !File("$name.$it.$extension").exists() + } + path = "$name.$fileIndex.$extension" + outputPath = moduleRoot.resolve(path) + } else { + outputPath = moduleRoot.resolve(path) + } + progress.text = "Writing file to disk..." + progress.fraction = 0.8 + + outputPath.parent.toFile().mkdirs() + WriteCommandAction.runWriteCommandAction(config?.project) { outputPath.toFile().writeText(generatedFile.code) } + Thread.sleep(100) + + return arrayOf(outputPath.toFile()) + } + + private fun generateFile( + basePath: String, + directive: String + ): ProjectFile { + require(directive.isNotBlank()) { "Directive cannot be empty" } + val model = AppSettingsState.instance.smartModel.chatModel() + val chatRequest = ChatRequest( + model = model.modelName, + temperature = AppSettingsState.instance.temperature, + messages = listOf( + ChatMessage( + Role.system, """ + You will interpret natural language requirements to create a new file. + Provide a new filename and the code to be written to the file. + Paths should be relative to the project root and should not exist. + Output the file path using the a line with the format "File: ". + Output the file code directly after the header line with no additional decoration. + """.trimIndent().toContentList(), null + ), + ChatMessage( + Role.user, """ + Create a new file based on the following directive: $directive + + The file location should be based on the selected path `$basePath` + """.trimIndent().toContentList(), null + ) + ) + ) + try { + val response = api.chat( + chatRequest, + AppSettingsState.instance.smartModel.chatModel() + ).choices.firstOrNull()?.message?.content?.trim() ?: throw IllegalStateException("Empty response from AI") + var outputPath = basePath + val header = response.lines().firstOrNull() ?: throw IllegalStateException("Invalid response format") + var body = response.lines().drop(1).joinToString("\n").trim().lines() + .dropWhile { it.startsWith("```") } + .dropLastWhile { it.startsWith("```") } + .joinToString("\n") + val pathPattern = FILE_PATH_REGEX.toRegex() + if (pathPattern.matches(header)) { + val match = pathPattern.matchEntire(header)!! + outputPath = match.groupValues[1] + } + require(body.isNotBlank()) { "Generated file content cannot be empty" } + return ProjectFile(path = outputPath, code = body) + } catch (e: Exception) { + log.error("Failed to generate file content", e) + throw IllegalStateException("Failed to generate file content: ${e.message}", e) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/generate/CreateImageAction.kt b/src/main/kotlin/aicoder/actions/generate/CreateImageAction.kt new file mode 100644 index 00000000..03cc1e84 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/generate/CreateImageAction.kt @@ -0,0 +1,202 @@ +package aicoder.actions.generate + +import aicoder.actions.BaseAction +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.util.ui.JBUI +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.config.AppSettingsState.Companion.imageModel +import com.simiacryptus.aicoder.util.IdeaOpenAIClient +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.actors.ImageActor +import com.simiacryptus.skyenet.core.actors.ImageResponse +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import org.slf4j.LoggerFactory +import java.awt.GridBagConstraints +import java.awt.GridBagLayout +import java.io.ByteArrayOutputStream +import java.io.IOException +import java.nio.file.Files +import java.nio.file.Path +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.util.concurrent.atomic.AtomicReference +import javax.imageio.ImageIO +import javax.swing.* + +class CreateImageAction : BaseAction() { + inner class ImageGenerationDialog(project: Project) : DialogWrapper(project) { + private val fileNameField = JTextField(generateDefaultFileName(), 20) + private val instructionsArea = JTextArea(3, 20) + + init { + log.debug("Initializing ImageGenerationDialog") + title = "Generate Image" + init() + } + + private fun generateDefaultFileName(): String { + val timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + return "generated_image_$timestamp.png" + } + + + override fun createCenterPanel(): JComponent { + return JPanel(GridBagLayout()).apply { + val c = GridBagConstraints() + c.fill = GridBagConstraints.HORIZONTAL + c.insets = JBUI.insets(5) + c.gridx = 0; c.gridy = 0 + add(JLabel("Output filename:"), c) + c.gridx = 1; c.gridy = 0 + add(fileNameField, c) + c.gridx = 0; c.gridy = 1 + add(JLabel("Special instructions:"), c) + c.gridx = 1; c.gridy = 1 + c.fill = GridBagConstraints.BOTH + add(JScrollPane(instructionsArea), c) + } + } + + fun getFileName() = fileNameField.text + fun getInstructions() = instructionsArea.text + } + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + log.info("Starting CreateImageAction handler") + val rootRef = AtomicReference(null) + val codeFiles: MutableSet = mutableSetOf() + val dialog = ImageGenerationDialog(e.project!!) + if (!dialog.showAndGet()) { + log.debug("Dialog cancelled by user") + return + } + UITools.runAsync(e.project, "Creating Image", true) { progress -> + try { + progress.text = "Analyzing code files..." + log.debug("Beginning code analysis") + fun codeSummary() = codeFiles.filter { + rootRef.get()?.resolve(it)?.toFile()?.exists() ?: false + }.associateWith { rootRef.get()?.resolve(it)?.toFile()?.readText(Charsets.UTF_8) }.entries.joinToString("\n\n") { (path, code) -> + val extension = path.toString().split('.').lastOrNull()?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ } + "# $path\n```$extension\n${code}\n```" + } + + val dataContext = e.dataContext + val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) + log.debug("Found ${virtualFiles?.size ?: 0} virtual files") + progress.text = "Determining root directory..." + val folder = UITools.getSelectedFolder(e) + rootRef.set( + if (null != folder) { + log.debug("Using selected folder as root: ${folder.toFile}") + folder.toFile.toPath() + } else if (1 == virtualFiles?.size) { + log.debug("Using parent of single file as root") + UITools.getSelectedFile(e)?.parent?.toNioPath() + } else { + log.debug("Using module root as root directory") + getModuleRootForFile(UITools.getSelectedFile(e)?.parent?.toFile ?: throw RuntimeException("No file selected")).toPath() + } + ) + progress.text = "Collecting files..." + + val root = rootRef.get() ?: throw RuntimeException("Root path not set") + if (!Files.exists(root)) { + throw IOException("Root directory does not exist: $root") + } + log.info("Using root directory: $root") + val files = getFiles(virtualFiles, root) + codeFiles.addAll(files) + log.debug("Collected ${codeFiles.size} code files") + progress.text = "Generating image..." + log.info("Starting image generation with ${codeFiles.size} files") + val imageActor = ImageActor( + prompt = """ + You are a technical drawing assistant. + You will be composing an image about the following code: + ${codeSummary()} + Special instructions: ${dialog.getInstructions()} + """.trimIndent(), + textModel = AppSettingsState.instance.smartModel.chatModel(), + imageModel = AppSettingsState.instance.mainImageModel.imageModel() + ).apply { setImageAPI(IdeaOpenAIClient.instance) } + log.debug("Sending request to image generation API") + val response = imageActor.answer(listOf(codeSummary(), dialog.getInstructions()), api) + log.debug("Image generation completed successfully") + val imagePath = root.resolve(dialog.getFileName()) + write(response, imagePath) + VirtualFileManager.getInstance().findFileByNioPath(imagePath)?.refresh(false, false) + } catch (ex: Throwable) { + when (ex) { + is IOException -> log.error("IO error during image creation: ${ex.message}", ex) + is SecurityException -> log.error("Security error during image creation: ${ex.message}", ex) + is IllegalArgumentException -> log.error("Invalid argument during image creation: ${ex.message}", ex) + else -> log.error("Unexpected error during image creation", ex) + } + UITools.showErrorDialog("Failed to create image: ${ex.message}", "Error") + } + } + } + + private fun write( + code: ImageResponse, path: Path + ) = try { + log.debug("Creating parent directories for: $path") + path.parent?.toFile()?.mkdirs() + val format = path.toString().split(".").last() + log.debug("Writing image in format: $format") + + val bytes = ByteArrayOutputStream().use { outputStream -> + if (!ImageIO.write( + code.image, format, outputStream + ) + ) { + throw IOException("Unsupported or invalid image format: $format") + } + outputStream.toByteArray() + } + path.toFile().writeBytes(bytes) + path + } catch (e: Exception) { + log.error("Failed to write image to $path", e) + when (e) { + is IOException -> throw IOException("Failed to write image: ${e.message}", e) + is SecurityException -> throw SecurityException("Security error writing image: ${e.message}", e) + else -> throw RuntimeException("Unexpected error writing image: ${e.message}", e) + } + } + + private fun getFiles( + virtualFiles: Array?, root: Path + ): MutableSet { + val codeFiles = mutableSetOf() + virtualFiles?.forEach { file -> + if (file.isDirectory) { + getFiles(file.children, root) + } else { + val relative = root.relativize(file.toNioPath()) + codeFiles.add(relative) //[] = file.contentsToByteArray().toString(Charsets.UTF_8) + } + } + return codeFiles + } + + override fun isEnabled(event: AnActionEvent): Boolean { + UITools.getSelectedFile(event) ?: return false + return true + } + + companion object { + private val log = LoggerFactory.getLogger(CreateImageAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/generate/GenerateDocumentationAction.kt b/src/main/kotlin/aicoder/actions/generate/GenerateDocumentationAction.kt new file mode 100644 index 00000000..4cd2412f --- /dev/null +++ b/src/main/kotlin/aicoder/actions/generate/GenerateDocumentationAction.kt @@ -0,0 +1,414 @@ +package aicoder.actions.generate + +import aicoder.actions.test.TestResultAutofixAction +import aicoder.actions.test.TestResultAutofixAction.Companion.getProjectStructure +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.ui.CheckBoxList +import com.intellij.ui.components.JBScrollPane +import com.intellij.ui.components.JBTextArea +import com.intellij.ui.components.JBTextField +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.config.Name +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.ApiModel +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import org.apache.commons.io.IOUtils +import java.awt.BorderLayout +import java.awt.Dimension +import java.io.File +import java.io.FileInputStream +import java.nio.file.Files +import java.nio.file.Path +import java.util.* +import java.util.concurrent.Executors +import java.util.concurrent.Future +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException +import javax.swing.* + + +class GenerateDocumentationAction : aicoder.actions.FileContextAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent): Boolean { + if (UITools.getSelectedFile(event)?.isDirectory == false) return false + return super.isEnabled(event) + } + + class SettingsUI { + @Name("Single Output File") + val singleOutputFile = JCheckBox("Produce a single output file", true) + + @Name("Files to Process") + val filesToProcess = CheckBoxList() + + @Name("AI Instruction") + val transformationMessage = JBTextArea(4, 40) + + @Name("Recent Instructions") + val recentInstructions = JComboBox() + + @Name("Output File") + val outputFilename = JBTextField() + + @Name("Output Directory") + val outputDirectory = JBTextField() + } + + class UserSettings( + var transformationMessage: String = "Create user documentation", + var outputFilename: String = "compiled_documentation.md", + var filesToProcess: List = listOf(), + var singleOutputFile: Boolean = true, + var outputDirectory: String = "docs/" + ) + + class Settings( + val settings: UserSettings? = null, + val project: Project? = null + ) + + override fun getConfig(project: Project?, e: AnActionEvent): Settings? { + val root = UITools.getSelectedFolder(e)?.toNioPath() + val files = Files.walk(root) + .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } + .toList().filterNotNull().sortedBy { it.toString() }.toTypedArray() + val settingsUI = SettingsUI().apply { + filesToProcess.setItems(files.toMutableList()) { path -> + root?.relativize(path)?.toString() ?: path.toString() + } + files.forEach { path -> + filesToProcess.setItemSelected(path, true) + } + outputDirectory.text = "docs/" + } + val mruDocumentationInstructions = AppSettingsState.instance.getRecentCommands("DocumentationInstructions") + settingsUI.recentInstructions.model = DefaultComboBoxModel( + mruDocumentationInstructions.getMostRecent(10).map { + "${it.split(" ").first()} ${it.split(" ").drop(1).joinToString(" ")}" + }.toTypedArray() + ) + settingsUI.recentInstructions.selectedIndex = -1 + settingsUI.recentInstructions.addActionListener { updateUIFromSelection(settingsUI) } + val dialog = DocumentationCompilerDialog(project, settingsUI) + dialog.show() + val settings: UserSettings = dialog.userSettings + settings.singleOutputFile = settingsUI.singleOutputFile.isSelected + settings.outputDirectory = settingsUI.outputDirectory.text + val result = dialog.isOK + settings.filesToProcess = when { + result -> files.filter { path -> settingsUI.filesToProcess.isItemSelected(path) }.sortedBy { it.toString() }.toList() + else -> listOf() + } + if (settings.filesToProcess.isEmpty()) return null + mruDocumentationInstructions.addInstructionToHistory("${settings.outputFilename} ${settings.transformationMessage}") + //.map { path -> return@map root?.resolve(path) }.filterNotNull() + return Settings(settings, project) + } + + private fun updateUIFromSelection(settingsUI: SettingsUI) { + val selected = settingsUI.recentInstructions.selectedItem as? String + if (selected != null) { + val parts = selected.split(" ", limit = 2) + if (parts.size == 2) { + settingsUI.outputFilename.text = parts[0] + settingsUI.transformationMessage.text = parts[1] + } else { + settingsUI.transformationMessage.text = selected + } + } else { + settingsUI.transformationMessage.text = "" + } + } + + override fun processSelection(state: SelectionState, config: Settings?, progress: ProgressIndicator): Array { + progress.fraction = 0.0 + if (config?.settings == null) { + // Dialog was cancelled, return empty array + return emptyArray().also { + // Ensure we don't attempt to open any files when dialog is cancelled + return@also + } + } + progress.text = "Initializing documentation generation..." + + val selectedFolder = state.selectedFile.toPath() + val gitRoot = TestResultAutofixAction.findGitRoot(selectedFolder) ?: selectedFolder + val outputDirectory = config.settings.outputDirectory + var outputPath = + selectedFolder.resolve(config.settings.outputFilename) + val relativePath = gitRoot.relativize(outputPath) + outputPath = gitRoot.resolve(outputDirectory).resolve(relativePath) + if (outputPath.toFile().exists()) { + val extension = outputPath.toString().split(".").last() + val name = outputPath.toString().split(".").dropLast(1).joinToString(".") + val fileIndex = (1..Int.MAX_VALUE).find { + !selectedFolder.resolve("$name.$it.$extension").toFile().exists() + } + outputPath = selectedFolder.resolve("$name.$fileIndex.$extension") + } + val executorService = Executors.newFixedThreadPool(4) + val transformationMessage = config.settings.transformationMessage + val markdownContent = TreeMap() + try { + val selectedPaths = config.settings.filesToProcess.sortedBy { it.toString() } + val partitionedPaths = Files.walk(selectedFolder) + .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } + .toList().sortedBy { it.toString() }.groupBy { selectedPaths.contains(it) } + val totalFiles = partitionedPaths[true]?.size ?: 0 + var processedFiles = 0 + val pathList = partitionedPaths[true] + ?.toList()?.filterNotNull() + ?.map> { path -> + executorService.submit { + var retries = 0 + val maxRetries = 3 + while (retries < maxRetries) { + try { + val fileContent = + IOUtils.toString(FileInputStream(path.toFile()), "UTF-8") ?: return@submit null + val transformContent = transformContent(path, fileContent, transformationMessage) + processTransformedContent( + path, + transformContent, + config, + selectedFolder, + gitRoot, + outputDirectory, + outputPath, + markdownContent + ) + synchronized(progress) { + processedFiles++ + progress.fraction = processedFiles.toDouble() / totalFiles + progress.text = "Processing file ${processedFiles} of ${totalFiles}" + } + return@submit path + } catch (e: Exception) { + retries++ + if (retries >= maxRetries) { + log.error("Failed to process file after $maxRetries attempts: $path", e) + return@submit null + } + log.warn("Error processing file: $path. Retrying (attempt $retries)", e) + Thread.sleep(1000L * retries) // Exponential backoff + } + } + null + } + }?.toTypedArray()?.map { future -> + try { + future.get(2, TimeUnit.MINUTES) // Set a timeout for each file processing + } catch (e: Exception) { + when (e) { + is TimeoutException -> log.error("File processing timed out", e) + else -> log.error("Error processing file", e) + } + null + } + }?.filterNotNull() ?: listOf() + if (config.settings.singleOutputFile == true) { + val sortedContent = markdownContent.entries.joinToString("\n\n") { (path, content) -> + "# $path\n\n$content" + } + outputPath.parent.toFile().mkdirs() + outputPath.parent.toFile().mkdirs() + Files.write(outputPath, sortedContent.toByteArray()) + open(config.project!!, outputPath) + return arrayOf(outputPath.toFile()) + } else { + val outputDir = selectedFolder.resolve(outputDirectory) + outputDir.toFile().mkdirs() + open(config.project!!, selectedFolder.resolve(outputDirectory)) + return pathList.map { it.toFile() }.toTypedArray() + } + } finally { + executorService.shutdown() + } + } + + private fun processTransformedContent( + path: Path, + transformContent: String, + config: Settings?, + selectedFolder: Path, + gitRoot: Path, + outputDirectory: String, + outputPath: Path, + markdownContent: TreeMap + ) { + if (config?.settings?.singleOutputFile == true) { + markdownContent[selectedFolder.relativize(path).toString()] = transformContent.replace("(?s)(? Unit + function = { + val file = outputPath.toFile() + if (file.exists()) { + // Ensure the IDE is ready for file operations + ApplicationManager.getApplication().invokeLater { + val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) + if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { + val localFileSystem = LocalFileSystem.getInstance() + // Refresh the file system to ensure the file is visible + val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) + virtualFile?.let { + FileEditorManager.getInstance(project).openFile(it, true) + } ?: scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } else { + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + } else { + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + } + + inner class DocumentationCompilerDialog(project: Project?, private val settingsUI: SettingsUI) : DialogWrapper(project) { + val userSettings = UserSettings() + + init { + title = "Compile Documentation" + // Set the default values for the UI elements from userSettings + settingsUI.transformationMessage.text = userSettings.transformationMessage + settingsUI.outputFilename.text = userSettings.outputFilename + settingsUI.outputDirectory.text = userSettings.outputDirectory + settingsUI.singleOutputFile.isSelected = userSettings.singleOutputFile + settingsUI.recentInstructions.addActionListener { + val selected = settingsUI.recentInstructions.selectedItem as? String + selected?.let { + updateUIFromSelection(settingsUI) + } + } + init() + } + + override fun createCenterPanel(): JComponent { + val panel = JPanel(BorderLayout()).apply { + val filesScrollPane = JBScrollPane(settingsUI.filesToProcess).apply { + preferredSize = Dimension(600, 400) // Increase the size for better visibility + } + add(filesScrollPane, BorderLayout.CENTER) // Make the files list the dominant element + + val optionsPanel = JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + border = BorderFactory.createEmptyBorder(10, 10, 10, 10) // Add some padding + add(JLabel("Recent Instructions")) + add(settingsUI.recentInstructions) + add(Box.createVerticalStrut(10)) + add(JLabel("AI Instruction")) + add(settingsUI.transformationMessage) + add(Box.createVerticalStrut(10)) + add(Box.createVerticalStrut(10)) // Add some vertical spacing + add(JLabel("Output File")) + add(settingsUI.outputFilename) + add(Box.createVerticalStrut(10)) + add(JLabel("Output Directory")) + add(settingsUI.outputDirectory) + add(Box.createVerticalStrut(10)) + add(settingsUI.singleOutputFile) + } + add(optionsPanel, BorderLayout.SOUTH) + } + return panel + } + + override fun doOKAction() { + if (!validateInput()) { + return + } + super.doOKAction() + userSettings.transformationMessage = settingsUI.transformationMessage.text + userSettings.outputFilename = settingsUI.outputFilename.text + userSettings.outputDirectory = settingsUI.outputDirectory.text + // Assuming filesToProcess already reflects the user's selection +// userSettings.filesToProcess = settingsUI.filesToProcess.selectedValuesList + userSettings.filesToProcess = + settingsUI.filesToProcess.items.filter { path -> settingsUI.filesToProcess.isItemSelected(path) } + userSettings.singleOutputFile = settingsUI.singleOutputFile.isSelected + } + + private fun validateInput(): Boolean { + if (settingsUI.transformationMessage.text.isBlank()) { + Messages.showErrorDialog("AI Instruction cannot be empty", "Input Error") + return false + } + if (settingsUI.outputFilename.text.isBlank()) { + Messages.showErrorDialog("Output File cannot be empty", "Input Error") + return false + } + if (settingsUI.outputDirectory.text.isBlank()) { + Messages.showErrorDialog("Output Directory cannot be empty", "Input Error") + return false + } + return true + } + } +} + +val CheckBoxList.items: List + get() { + val items = mutableListOf() + for (i in 0 until model.size) { + items.add(getItemAt(i)!!) + } + return items + } \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/generate/GenerateRelatedFileAction.kt b/src/main/kotlin/aicoder/actions/generate/GenerateRelatedFileAction.kt new file mode 100644 index 00000000..13658b6f --- /dev/null +++ b/src/main/kotlin/aicoder/actions/generate/GenerateRelatedFileAction.kt @@ -0,0 +1,190 @@ +package aicoder.actions.generate + +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.LocalFileSystem +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.config.Name +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.ApiModel +import com.simiacryptus.jopenai.models.ApiModel.ChatMessage +import com.simiacryptus.jopenai.models.ApiModel.Role +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.util.ClientUtil.toContentList +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import org.apache.commons.io.FileUtils +import org.apache.commons.io.IOUtils +import java.io.File +import java.io.FileInputStream +import java.nio.file.Path +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicReference +import javax.swing.JTextArea + +class GenerateRelatedFileAction : aicoder.actions.FileContextAction() { + private val log = Logger.getInstance(GenerateRelatedFileAction::class.java) + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + override fun isEnabled(event: AnActionEvent): Boolean { + return UITools.getSelectedFiles(event).size == 1 && super.isEnabled(event) + } + + data class ProjectFile( + val path: String = "", + val code: String = "" + ) + + class SettingsUI { + @Name("Directive") + var directive: JTextArea = JTextArea( + """ + Create test cases + """.trimIndent(), + 3, + 120 + ) + } + + class UserSettings( + var directive: String = "", + ) + + class Settings( + val settings: UserSettings? = null, + val project: Project? = null + ) + + override fun getConfig(project: Project?, e: AnActionEvent): Settings { + return Settings( + UITools.showDialog( + project, + SettingsUI::class.java, + UserSettings::class.java, + "Create Analogue File" + ), project + ) + } + + override fun processSelection(state: SelectionState, config: Settings?, progress: ProgressIndicator): Array { + try { + progress.isIndeterminate = false + progress.text = "Reading source file..." + progress.fraction = 0.2 + val root = getModuleRootForFile(state.selectedFile).toPath() + val selectedFile = state.selectedFile + val analogue = generateFile( + baseFile = ProjectFile( + path = root.relativize(selectedFile.toPath()).toString(), + code = IOUtils.toString(FileInputStream(selectedFile), "UTF-8") + ), + directive = config?.settings?.directive ?: "", + progress = progress + ) + progress.text = "Generating output file..." + progress.fraction = 0.6 + var outputPath = root.resolve(analogue.path) + if (outputPath.toFile().exists()) { + val extension = outputPath.toString().split(".").last() + val name = outputPath.toString().split(".").dropLast(1).joinToString(".") + val fileIndex = (1..Int.MAX_VALUE).find { + !root.resolve("$name.$it.$extension").toFile().exists() + } + outputPath = root.resolve("$name.$fileIndex.$extension") + } + progress.text = "Writing output file..." + progress.fraction = 0.8 + outputPath.parent.toFile().mkdirs() + FileUtils.write(outputPath.toFile(), analogue.code, "UTF-8") + open(config?.project!!, outputPath) + return arrayOf(outputPath.toFile()) + } catch (e: Exception) { + log.error("Failed to generate related file", e) + throw e + } + } + + private fun generateFile(baseFile: ProjectFile, directive: String, progress: ProgressIndicator): ProjectFile = try { + progress.text = "Generating content with AI..." + progress.fraction = 0.4 + val model = AppSettingsState.instance.smartModel.chatModel() + val chatRequest = ApiModel.ChatRequest( + model = model.modelName, + temperature = AppSettingsState.instance.temperature, + messages = listOf( + ChatMessage( + Role.system, """ + You will combine natural language instructions with a user provided code example to create a new file. + Provide a new filename and the code to be written to the file. + Paths should be relative to the project root and should not exist. + Output the file path using the a line with the format "File: ". + Output the file code directly after the header line with no additional decoration. + """.trimIndent().toContentList(), null + ), + ChatMessage( + Role.user, (""" + Create a new file based on the following directive: """.trimIndent() + directive + """ + + The file should be based on `""".trimIndent() + baseFile.path + """` which contains the following code: + + ``` + """.trimIndent() + baseFile.code + """ + ``` + """.trimIndent()).toContentList(), null + ) + ) + ) + val response = api.chat(chatRequest, model).choices.firstOrNull()?.message?.content?.trim() ?: throw IllegalStateException("No response from API") + var outputPath = baseFile.path + val header = response?.split("\n")?.first() + var body = response?.split("\n")?.drop(1)?.joinToString("\n")?.trim() + if (body?.contains("```") == true) { + body = body.split("```.*".toRegex()).drop(1).firstOrNull()?.trim() ?: body + } + val pathPattern = "File(?:name)?: ['\"]?([^'\"]+)['\"]?".toRegex() + val matcher = pathPattern.find(header ?: "") + if (matcher != null) { + outputPath = matcher.groupValues[1].trim() + } + ProjectFile( + path = outputPath, + code = body ?: "" + ) + } catch (e: Exception) { + throw e + } + + companion object { + fun open(project: Project, outputPath: Path) { + val functionRef = AtomicReference<(() -> Unit)?>(null) + val function: () -> Unit = { + val file = outputPath.toFile() + if (file.exists()) { + // Ensure the IDE is ready for file operations + ApplicationManager.getApplication().invokeLater { + val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) + if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { + val localFileSystem = LocalFileSystem.getInstance() + // Refresh the file system to ensure the file is visible + val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) + virtualFile?.let { + FileEditorManager.getInstance(project).openFile(it, true) + } ?: scheduledPool.schedule(functionRef.get()!!, 100, TimeUnit.MILLISECONDS) + } else { + scheduledPool.schedule(functionRef.get()!!, 100, TimeUnit.MILLISECONDS) + } + } + } else { + scheduledPool.schedule(functionRef.get()!!, 100, TimeUnit.MILLISECONDS) + } + } + functionRef.set(function) + scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/git/ChatWithCommitAction.kt b/src/main/kotlin/aicoder/actions/git/ChatWithCommitAction.kt new file mode 100644 index 00000000..50c081e0 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/git/ChatWithCommitAction.kt @@ -0,0 +1,125 @@ +package aicoder.actions.git + +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.vcs.VcsDataKeys +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.CodeChatSocketManager +import com.simiacryptus.aicoder.util.IdeaChatClient +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.util.IterativePatchUtil +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import java.io.File +import java.text.SimpleDateFormat + +val String.isBinary: Boolean + get() { + val binary = this.toByteArray().filter { it < 0x20 || it > 0x7E } + return binary.size > this.length / 10 + } + +class ChatWithCommitAction : AnAction() { + private val logger = Logger.getInstance(ChatWithCommitAction::class.java) + + override fun actionPerformed(e: AnActionEvent) { + logger.info("Comparing selected revision with the current working copy") + val files = expand(e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)) + val changes = e.getData(VcsDataKeys.CHANGES) + Thread { + try { + val map = changes?.toList() + ?.associateBy { (it.beforeRevision?.file ?: it.afterRevision?.file)!!.toString() } + val msg = map?.entries + ?.filter { (file, change) -> + val find = files?.find { it.toNioPath().toFile().absolutePath == File(file).absolutePath } + find != null + } + ?.joinToString("\n\n") { (file, change) -> + val before = change.beforeRevision?.content + val after = change.afterRevision?.content + if ((before ?: after)!!.isBinary) + return@joinToString "# Binary: ${change.afterRevision?.file}".replace("\n", "\n ") + if (before == null) return@joinToString "# Deleted: ${change.afterRevision?.file}\n${after}".replace( + "\n", + "\n " + ) + if (after == null) return@joinToString "# Added: ${change.beforeRevision?.file}\n${before}".replace( + "\n", + "\n " + ) + val diff = IterativePatchUtil.generatePatch(before, after) + "# Change: ${change.beforeRevision?.file}\n$diff".replace("\n", "\n ") + } + + // Open chat with the diff information + openChatWithDiff(e, msg ?: "No changes found") + } catch (e: Throwable) { + logger.error("Error comparing changes", e) + } + }.start() + } + + private fun openChatWithDiff(e: AnActionEvent, diffInfo: String) { + val session = Session.newGlobalID() + SessionProxyServer.agents[session] = CodeChatSocketManager( + session = session, + language = "diff", + codeSelection = diffInfo, + filename = "commit_changes.diff", + api = IdeaChatClient.instance, + model = AppSettingsState.instance.smartModel.chatModel(), + storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + val server = AppServer.getServer(e.project) + + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + logger.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + logger.warn("Error opening browser", e) + } + }.start() + } + + private fun expand(data: Array?): Array? { + return data?.flatMap { + if (it.isDirectory) { + expand(it.children.toList().toTypedArray())?.toList() ?: listOf() + } else { + listOf(it) + } + }?.toTypedArray() + } + + override fun update(e: AnActionEvent) { + e.presentation.isEnabledAndVisible = e.getData(PlatformDataKeys.PROJECT) != null && + e.getData(VcsDataKeys.VCS)?.name != "Git" + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/git/ChatWithCommitDiffAction.kt b/src/main/kotlin/aicoder/actions/git/ChatWithCommitDiffAction.kt new file mode 100644 index 00000000..c2b58b80 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/git/ChatWithCommitDiffAction.kt @@ -0,0 +1,150 @@ +package aicoder.actions.git + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.LocalFilePath +import com.intellij.openapi.vcs.ProjectLevelVcsManager +import com.intellij.openapi.vcs.VcsDataKeys +import com.intellij.openapi.vcs.changes.Change +import com.intellij.openapi.vcs.changes.ChangeListManager +import com.intellij.openapi.vcs.changes.CurrentContentRevision +import com.intellij.openapi.vcs.changes.TextRevisionNumber +import com.intellij.openapi.vcs.history.VcsRevisionNumber +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.CodeChatSocketManager +import com.simiacryptus.aicoder.util.IdeaChatClient +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import java.text.SimpleDateFormat +import com.intellij.openapi.application.ApplicationManager as IntellijAppManager + +class ChatWithCommitDiffAction : BaseAction( + name = "Chat with Commit Diff", + description = "Opens a chat interface to discuss commit differences" +) { + companion object { + private val log = Logger.getInstance(ChatWithCommitDiffAction::class.java) + } + + override fun handle(e: AnActionEvent) { + log.info("Comparing selected commit with the current HEAD") + val project = e.project ?: return + val selectedCommit = e.getData(VcsDataKeys.VCS_REVISION_NUMBER) ?: return + val vcsManager = ProjectLevelVcsManager.getInstance(project) + val vcs = vcsManager.allActiveVcss.firstOrNull() ?: run { + UITools.showErrorDialog("No active VCS found", "Error") + return + } + + UITools.runAsync(project, "Comparing Changes", true) { progress -> + try { + progress.text = "Retrieving changes between commits..." + val diffInfo = getChangesBetweenCommits(project, selectedCommit).ifEmpty { "No changes found" } + progress.text = "Opening chat interface..." + openChatWithDiff(e, diffInfo) + } catch (e: Throwable) { + log.error("Error comparing changes", e) + UITools.showErrorDialog("Error comparing changes: ${e.message}", "Error") + } + } + } + + + private fun openChatWithDiff(e: AnActionEvent, diffInfo: String) { + val session = Session.newGlobalID() + SessionProxyServer.agents[session] = CodeChatSocketManager( + session = session, + language = "diff", + codeSelection = diffInfo, + filename = "commit_changes.diff", + api = IdeaChatClient.instance, + model = AppSettingsState.instance.smartModel.chatModel(), + storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + val server = AppServer.getServer(e.project) + + IntellijAppManager.getApplication().executeOnPooledThread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + } + } + + private fun getChangesBetweenCommits(project: Project, selectedCommit: VcsRevisionNumber): String { + val commitID = (selectedCommit as TextRevisionNumber).asString() + val changeListManager = ChangeListManager.getInstance(project) + val changes = changeListManager.allChanges + return changes.joinToString("\n") { change: Change -> + buildString { + appendLine("File: ${change.virtualFile?.path ?: "Unknown"}") + appendLine("Type: ${change.type}") + appendLine(getDiffForChange(project, change, selectedCommit) ?: "No diff available") + } + } + } + + private fun getDiffForChange(project: Project, change: Change, selectedCommit: VcsRevisionNumber): String? { + val file = change.virtualFile ?: return null + val currentContent = change.afterRevision?.content ?: return null + val selectedContent = getContentForRevision(project, file, selectedCommit) ?: return null + return createSimpleDiff(currentContent, selectedContent) + } + + private fun getContentForRevision(project: Project, file: VirtualFile, revisionNumber: VcsRevisionNumber): String? { + try { + val contentRevision = CurrentContentRevision(LocalFilePath(file.path, file.isDirectory)) + return contentRevision.content + } catch (e: Exception) { + log.error("Error getting content for revision", e) + return null + } + } + + private fun createSimpleDiff(currentContent: String, selectedContent: String): String { + val currentLines = currentContent.lines() + val selectedLines = selectedContent.lines() + val diff = StringBuilder() + for ((index, line) in currentLines.withIndex()) { + if (index >= selectedLines.size) { + diff.appendLine("+ $line") + } else if (line != selectedLines[index]) { + diff.appendLine("- ${selectedLines[index]}") + diff.appendLine("+ $line") + } + } + if (selectedLines.size > currentLines.size) { + for (i in currentLines.size until selectedLines.size) { + diff.appendLine("- ${selectedLines[i]}") + } + } + return diff.toString() + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/git/ChatWithWorkingCopyDiffAction.kt b/src/main/kotlin/aicoder/actions/git/ChatWithWorkingCopyDiffAction.kt new file mode 100644 index 00000000..4b21a372 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/git/ChatWithWorkingCopyDiffAction.kt @@ -0,0 +1,135 @@ +package aicoder.actions.git + +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.vcs.VcsDataKeys +import com.intellij.openapi.vcs.changes.ChangeListManager +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.CodeChatSocketManager +import com.simiacryptus.aicoder.util.IdeaChatClient +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import java.text.SimpleDateFormat +import javax.swing.JOptionPane + +class ChatWithWorkingCopyDiffAction : AnAction() { + companion object { + private val log = Logger.getInstance(ChatWithWorkingCopyDiffAction::class.java) + } + + override fun actionPerformed(e: AnActionEvent) { + log.info("Comparing HEAD with the working copy") + val project = e.project ?: return + val files = e.getData(VcsDataKeys.VIRTUAL_FILES)?.firstOrNull() + val changeListManager = ChangeListManager.getInstance(project) + + Thread { + try { + val diffInfo = getWorkingCopyDiff(changeListManager) + openChatWithDiff(e, diffInfo) + } catch (e: Throwable) { + log.error("Error comparing changes", e) + JOptionPane.showMessageDialog(null, e.message, "Error", JOptionPane.ERROR_MESSAGE) + } + }.start() + } + + private fun openChatWithDiff(e: AnActionEvent, diffInfo: String) { + val session = Session.newGlobalID() + SessionProxyServer.agents[session] = CodeChatSocketManager( + session = session, + language = "diff", + codeSelection = diffInfo, + filename = "working_copy_changes.diff", + api = IdeaChatClient.instance, + model = AppSettingsState.instance.smartModel.chatModel(), + storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + val server = AppServer.getServer(e.project) + + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + + private fun getWorkingCopyDiff(changeListManager: ChangeListManager): String { + val changes = changeListManager.allChanges + return changes.joinToString("\n\n") { change -> + val diffForChange = getDiffForChange(change) + "File: ${change.virtualFile?.path ?: "Unknown"}\n" + + "Type: ${change.type}\n" + + (diffForChange ?: "No diff available") + }.ifEmpty { "No changes found" } + } + + private fun getDiffForChange(change: com.intellij.openapi.vcs.changes.Change): String? { + val beforeRevision = change.beforeRevision + val afterRevision = change.afterRevision + + if (beforeRevision == null && afterRevision == null) { + return null + } + + val beforeContent = beforeRevision?.content ?: "" + val afterContent = afterRevision?.content ?: "" + + return createSimpleDiff(beforeContent, afterContent) + } + + private fun createSimpleDiff(beforeContent: String, afterContent: String): String { + val beforeLines = beforeContent.lines() + val afterLines = afterContent.lines() + val diff = StringBuilder() + + for ((index, line) in afterLines.withIndex()) { + if (index >= beforeLines.size) { + diff.appendLine("+ $line") + } else if (line != beforeLines[index]) { + diff.appendLine("- ${beforeLines[index]}") + diff.appendLine("+ $line") + } + } + + if (beforeLines.size > afterLines.size) { + for (i in afterLines.size until beforeLines.size) { + diff.appendLine("- ${beforeLines[i]}") + } + } + + return diff.toString() + } + + override fun update(e: AnActionEvent) { + val project = e.project ?: return + val vcs = e.getData(VcsDataKeys.VCS) + e.presentation.isEnabledAndVisible = project != null && vcs != null + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/git/ReplicateCommitAction.kt b/src/main/kotlin/aicoder/actions/git/ReplicateCommitAction.kt new file mode 100644 index 00000000..cbfda656 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/git/ReplicateCommitAction.kt @@ -0,0 +1,415 @@ +package aicoder.actions.git + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.vcs.VcsDataKeys +import com.intellij.openapi.vcs.changes.Change +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.diff.AddApplyFileDiffLinks +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.describe.Description +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.AgentPatterns +import com.simiacryptus.skyenet.Retryable +import com.simiacryptus.skyenet.core.actors.ParsedActor +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.core.util.FileValidationUtils +import com.simiacryptus.skyenet.core.util.IterativePatchUtil +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.session.SessionTask +import com.simiacryptus.util.JsonUtil +import org.slf4j.LoggerFactory +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.text.SimpleDateFormat +import kotlin.io.path.ExperimentalPathApi +import kotlin.io.path.walk + +class ReplicateCommitAction : BaseAction() { + private val logger = Logger.getInstance(ReplicateCommitAction::class.java) + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(event: AnActionEvent) { + val project = event.project ?: return + try { + val settings = getUserSettings(event) ?: run { + Messages.showErrorDialog(project, "Could not determine working directory", "Configuration Error") + return + } + + val dataContext = event.dataContext + val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) + val folder = UITools.getSelectedFolder(event) + var root = if (null != folder) { + folder.toFile.toPath() + } else { + project.basePath?.let { File(it).toPath() } + }!! + + val virtualFiles1 = event.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) + val files = expand(virtualFiles1) + val changes = event.getData(VcsDataKeys.CHANGES) + val session = Session.newGlobalID() + + UITools.run(project, "Replicating Commit", true) { progress -> + progress.text = "Generating diff info..." + val diffInfo = generateDiffInfo(files, changes) + progress.text = "Creating patch application..." + val patchApp = object : PatchApp(root.toFile(), session, settings, diffInfo) { + override fun codeFiles() = getFiles(virtualFiles) + .filter { it.toFile().length() < 1024 * 1024 / 2 } // Limit to 0.5MB + .map { root.relativize(it) ?: it }.toSet() + + override fun codeSummary(paths: List): String = paths + .filter { it.toFile().exists() } + .joinToString("\n\n") { path -> + "# ${settings.workingDirectory.toPath().relativize(path)}\n$tripleTilde${path.toString().split('.').lastOrNull()}\n${ + path.toFile().readText(Charsets.UTF_8) + }\n$tripleTilde" + } + + override fun projectSummary(): String { + val codeFiles = codeFiles() + val str = codeFiles + .asSequence() + .filter { settings.workingDirectory.toPath()?.resolve(it)?.toFile()?.exists() == true } + .distinct().sorted() + .joinToString("\n") { path -> + "* ${path} - ${ + settings.workingDirectory.toPath()?.resolve(path)?.toFile()?.length() ?: "?" + } bytes".trim() + } + return str + } + } + progress.text = "Setting up session..." + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = patchApp + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + } + ApplicationManager.getApplication().executeOnPooledThread { + Thread.sleep(500) + try { + val server = AppServer.getServer(project) + val uri = server.server.uri.resolve("/#$session") + logger.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + logger.error("Error opening browser", e) + UITools.showErrorDialog("Failed to open browser: ${e.message}", "Error") + } + } + } catch (e: Exception) { + logger.error("Error in ReplicateCommitAction", e) + Messages.showErrorDialog(project, "Operation failed: ${e.message}", "Error") + } + } + + // Add proper enablement logic + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val project = event.project ?: return false + val changes = event.getData(VcsDataKeys.CHANGES) + return changes != null && changes.isNotEmpty() + } + + private fun generateDiffInfo(files: Array?, changes: Array?): String { + val map = changes?.toList() + ?.associateBy { (it.beforeRevision?.file ?: it.afterRevision?.file)!!.toString() } + val entries = map?.entries + ?.filter { (file, change) -> + try { + val find = files?.find { it.toNioPath().toFile().absolutePath == File(file).absolutePath } + find != null + } catch (e: Exception) { + logger.error("Error comparing changes", e) + false + } + } + return entries + ?.joinToString("\n\n") { (file, change) -> + val before = change.beforeRevision?.content + val after = change.afterRevision?.content + if ((before ?: after)!!.isBinary) + return@joinToString "# Binary: ${change.afterRevision?.file}".replace("\n", "\n ") + if (before == null) return@joinToString "# Deleted: ${change.afterRevision?.file}\n${after}".replace( + "\n", + "\n " + ) + if (after == null) return@joinToString "# Added: ${change.beforeRevision?.file}\n${before}".replace( + "\n", + "\n " + ) + val diff = IterativePatchUtil.generatePatch(before, after) + "# Change: ${change.beforeRevision?.file}\n$diff".replace("\n", "\n ") + } ?: "No changes found" + } + + abstract inner class PatchApp( + override val root: File, + val session: Session, + val settings: Settings, + val diffInfo: String, + ) : ApplicationServer( + applicationName = "Replicate Commit", + path = "/replicateCommit", + showMenubar = false, + ) { + abstract fun codeFiles(): Set + abstract fun codeSummary(paths: List): String + override val singleInput = true + override val stickyInput = false + + override fun userMessage( + session: Session, + user: User?, + userMessage: String, + ui: ApplicationInterface, + api: API + ) { + val task = ui.newTask() + task.echo(userMessage) + Thread { + run(ui, task, session, settings, userMessage, diffInfo) + }.start() + task.placeholder + } + + abstract fun projectSummary(): String + } + + private fun PatchApp.run( + ui: ApplicationInterface, + task: SessionTask, + session: Session, + settings: Settings, + userMessage: String = "", + diffInfo: String + ) { + try { + val planTxt = projectSummary() + task.add(renderMarkdown(planTxt)) + Retryable(ui, task) { + val plan = ParsedActor( + resultClass = ParsedTasks::class.java, + prompt = """ + You are a helpful AI that helps people with coding. + + You will be answering questions about the following project: + + Project Root: """.trimIndent() + (settings.workingDirectory.absolutePath ?: "") + """ + + Files: + """.trimIndent() + planTxt + """ + + Given the request, identify one or more tasks. + For each task: + 1) predict the files that need to be fixed + 2) predict related files that may be needed to debug the issue + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel() + ).answer( + listOf( + "We want to create a change based on the following prior commit:\n\n$tripleTilde\n$diffInfo\n$tripleTilde\n\nThe change should implement the user's request:\n\n$tripleTilde\n$userMessage\n$tripleTilde" + ), api = api + ) + task.add( + AgentPatterns.displayMapInTabs( + mapOf( + "Text" to renderMarkdown(plan.text, ui = ui), + "JSON" to renderMarkdown( + "${tripleTilde}json\n${JsonUtil.toJson(plan.obj)}\n$tripleTilde", + ui = ui + ), + ) + ) + ) + plan.obj.errors?.map { planTask -> + Retryable(ui, task) { + val paths = + ((planTask.fixFiles ?: emptyList()) + (planTask.relatedFiles ?: emptyList())).flatMap { + toPaths(settings.workingDirectory.toPath(), it) + } + val codeSummary = codeSummary(paths) + val response = SimpleActor( + prompt = """ + You are a helpful AI that helps people with coding. + + You will be answering questions about the following code: + + """.trimIndent() + codeSummary + """ + + + Response should use one or more code patches in diff format within """.trimIndent() + tripleTilde + """diff code blocks. + Each diff should be preceded by a header that identifies the file being modified. + The diff format should use + for line additions, - for line deletions. + The diff should include 2 lines of context before and after every change. + + Example: + + Here are the patches: + + ### src/utils/exampleUtils.js + """.trimIndent() + tripleTilde + """diff + // Utility functions for example feature + const b = 2; + function exampleFunction() { + - return b + 1; + + return b + 2; + } + """.trimIndent() + tripleTilde + """ + + ### tests/exampleUtils.test.js + """.trimIndent() + tripleTilde + """diff + // Unit tests for exampleUtils + const assert = require('assert'); + const { exampleFunction } = require('../src/utils/exampleUtils'); + + describe('exampleFunction', () => { + - it('should return 3', () => { + + it('should return 4', () => { + assert.equal(exampleFunction(), 3); + }); + }); + """.trimIndent() + tripleTilde + """ + + If needed, new files can be created by using code blocks labeled with the filename in the same manner. + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel() + ).answer( + listOf( + """ + We are working on executing the following directive: + + """.trimIndent() + tripleTilde + """ + """.trimIndent() + userMessage + """ + """.trimIndent() + tripleTilde + """ + + Focus on the task at hand: + """.trimIndent() + (planTask.message?.replace("\n", "\n ") ?: "") + ), api = api + ) + var markdown = AddApplyFileDiffLinks.instrumentFileDiffs( + ui.socketManager!!, + root = root.toPath(), + response = response, + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + task.complete("$path Updated") + } + }, + ui = ui, + api = api, + ) + "
${renderMarkdown(markdown!!)}
" + } + "" + }?.joinToString { it } ?: "" + } + } catch (e: Exception) { + task.error(ui, e) + } + } + + data class ParsedTasks( + val errors: List? = null + ) + + data class ParsedTask( + @Description("The task to be performed") + val message: String? = null, + @Description("Files identified as needing modification and issue-related files") + val relatedFiles: List? = null, + @Description("Files identified as needing modification and issue-related files") + val fixFiles: List? = null + ) + + data class Settings( + var workingDirectory: File, + ) + + private fun getFiles( + virtualFiles: Array? + ): MutableSet { + val codeFiles = mutableSetOf() // Set to avoid duplicates + virtualFiles?.forEach { file -> + if (file.isDirectory) { + if (file.name.startsWith(".")) return@forEach + if (FileValidationUtils.Companion.isGitignore(file.toNioPath())) return@forEach + codeFiles.addAll(getFiles(file.children)) + } else { + codeFiles.add((file.toNioPath())) + } + } + return codeFiles + } + + private fun getUserSettings(event: AnActionEvent?): Settings? { + val root = UITools.getSelectedFolder(event ?: return null)?.toNioPath() ?: event.project?.basePath?.let { File(it).toPath() } + val files = UITools.getSelectedFiles(event).map { it.path.let { File(it).toPath() } }.toMutableSet() + if (files.isEmpty()) Files.walk(root) + .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } + .toList().filterNotNull().forEach { files.add(it) } + return Settings(root?.toFile() ?: return null) + } + + private fun expand(data: Array?): Array? { + return data?.flatMap { + if (it.isDirectory) { + expand(it.children.toList().toTypedArray())?.toList() ?: listOf() + } else { + listOf(it) + } + }?.toTypedArray() + } + + companion object { + private val log = LoggerFactory.getLogger(ReplicateCommitAction::class.java) + val tripleTilde = "`" + "``" // This is a workaround for the markdown parser when editing this file + + @OptIn(ExperimentalPathApi::class) + fun toPaths(root: Path, it: String): Iterable { + // Expand any wildcards + if (it.contains("*")) { + val prefix = it.substringBefore("*") + val suffix = it.substringAfter("*") + val files = root.walk().toList() + val pathList = files.filter { + it.toString().startsWith(prefix) && it.toString().endsWith(suffix) + }.toList() + return pathList + } else { + return listOf(Path.of(it)) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/knowledge/CreateProjectorFromQueryIndexAction.kt b/src/main/kotlin/aicoder/actions/knowledge/CreateProjectorFromQueryIndexAction.kt new file mode 100644 index 00000000..0a0f66c0 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/knowledge/CreateProjectorFromQueryIndexAction.kt @@ -0,0 +1,127 @@ +package aicoder.actions.knowledge + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.aicoder.util.findRecursively +import com.simiacryptus.skyenet.apps.parse.DocumentRecord +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.util.TensorflowProjector +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager +import com.simiacryptus.skyenet.webui.session.SocketManager +import org.slf4j.LoggerFactory +import java.text.SimpleDateFormat + +class CreateProjectorFromQueryIndexAction : BaseAction() { + data class ProjectorConfig( + val sessionId: Session = Session.newGlobalID(), + val applicationName: String = "Projector" + ) + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val selectedFiles = UITools.getSelectedFiles(event) + val processableFiles = selectedFiles.flatMap { file -> + when { + file.isDirectory -> file.findRecursively { it.name.endsWith(".index.data") } + file.name.endsWith(".index.data") -> listOf(file) + else -> emptyList() + } + } + return processableFiles.isNotEmpty() + } + + override fun handle(e: AnActionEvent) { + val processableFiles = getProcessableFiles(e) + if (processableFiles.isEmpty()) { + UITools.showErrorDialog("Please select a valid query index file (.index.data).", "Invalid Selection") + return + } + + UITools.runAsync(e.project, "Creating Projector", true) { indicator -> + try { + indicator.isIndeterminate = false + indicator.fraction = 0.0 + indicator.text = "Reading records..." + + val records = processableFiles.flatMap { DocumentRecord.readBinary(it.path) } + val config = ProjectorConfig() + indicator.text = "Setting up projector..." + + ApplicationServer.appInfoMap[config.sessionId] = AppInfoData( + applicationName = config.applicationName, + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + + SessionProxyServer.chats[config.sessionId] = object : ApplicationServer( + applicationName = config.applicationName, + path = "/projector", + showMenubar = false, + ) { + override fun newSession( + user: User?, + session: Session + ): SocketManager { + val socketManager = super.newSession(user, session) + val ui = (socketManager as ApplicationSocketManager).applicationInterface + val projector = TensorflowProjector(api2, dataStorage, session, ui, null) + val result = projector.writeTensorflowEmbeddingProjectorHtmlFromRecords(records) + val task = ui.newTask(true) + task.complete(result) + return socketManager + } + } + SessionProxyServer.metadataStorage.setSessionName( + null, + config.sessionId, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + indicator.fraction = 1.0 + indicator.text = "Opening browser..." + + val server = AppServer.getServer(e.project) + + ApplicationManager.getApplication().executeOnPooledThread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#${config.sessionId}") + BaseAction.log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + } + + } catch (ex: Exception) { + log.error("Error during projector creation", ex) + UITools.showErrorDialog("Error during projector creation: ${ex.message}", "Projector Creation Failed") + } + } + } + + private fun getProcessableFiles(e: AnActionEvent) = UITools.getSelectedFiles(e).flatMap { file -> + when { + file.isDirectory -> file.findRecursively { it.name.endsWith(".index.data") } + file.name.endsWith(".index.data") -> listOf(file) + else -> emptyList() + } + } + + companion object { + private val log = LoggerFactory.getLogger(CreateProjectorFromQueryIndexAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/knowledge/DocumentDataExtractorAction.kt b/src/main/kotlin/aicoder/actions/knowledge/DocumentDataExtractorAction.kt new file mode 100644 index 00000000..5660c6cf --- /dev/null +++ b/src/main/kotlin/aicoder/actions/knowledge/DocumentDataExtractorAction.kt @@ -0,0 +1,150 @@ +package aicoder.actions.knowledge + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.aicoder.util.findRecursively +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.apps.parse.DocumentParserApp +import com.simiacryptus.skyenet.apps.parse.DocumentParsingModel +import com.simiacryptus.skyenet.apps.parse.ParsingModel +import com.simiacryptus.skyenet.apps.parse.ParsingModel.DocumentData +import com.simiacryptus.skyenet.apps.parse.ParsingModelType +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.file.DataStorage +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import java.io.File +import java.text.SimpleDateFormat + +class DocumentDataExtractorAction : BaseAction( + name = "Extract Document Data", description = "Extracts structured data from documents using AI" +) { + val path = "/pdfExtractor" + private var settings = DocumentParserApp.Settings() + private var modelType = ParsingModelType.Document + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val selectedFiles = UITools.getSelectedFiles(event) + val processableFiles = selectedFiles.flatMap { file -> + when { + file.isDirectory -> file.findRecursively { isValidFileType(it.name) } + isValidFileType(file.name) -> listOf(file) + else -> emptyList() + } + } + return processableFiles.isNotEmpty() + } + + fun isValidFileType(filename: String): Boolean = when { + filename.endsWith(".parsed.json", ignoreCase = true) -> false + filename.endsWith(".data", ignoreCase = true) -> false + filename.split('.').lastOrNull()?.let { + setOf( + /* Images */ + "jpg", "jpeg", "png", "gif", "bmp", "tiff", "tif", "webp", "svg", + /* Videos */ + "mp4", "webm", "ogg", "avi", "mov", "flv", "mkv", "wmv", "mpg", "mpeg", "3gp", "3g2", + /* Audio */ + "mp3", "wav", "ogg", "flac", "aac", "wma", "m4a", "aiff", "alac", + /* Archives */ + "zip", "rar", "7z", "tar", "gz", "bz2", "xz", + /* Executables */ + "exe", "dmg", "apk", "msi", "deb", + ).contains(it) + } == true -> false + + filename.endsWith(".pdf", ignoreCase = true) -> true + filename.endsWith(".txt", ignoreCase = true) -> true + filename.endsWith(".html", ignoreCase = true) -> true + filename.endsWith(".htm", ignoreCase = true) -> true + filename.endsWith(".md", ignoreCase = true) -> true + else -> true // Allow other files for code parsing + } + + override fun handle(e: AnActionEvent) { + val selectedFiles = UITools.getSelectedFiles(e) + val processableFiles = selectedFiles.flatMap { file -> + when { + file.isDirectory -> file.findRecursively { isValidFileType(it.name) } + isValidFileType(file.name) -> listOf(file) + else -> emptyList() + } + } + if (processableFiles.isEmpty()) { + UITools.showErrorDialog("No valid files found in selection.", "No Valid Files") + return + } + val selectedFile = processableFiles.first() + val configDialog = DocumentDataExtractorConfigDialog(e.project, settings, modelType) + if (!configDialog.showAndGet()) return + settings = configDialog.settings + modelType = configDialog.modelType as ParsingModelType + + UITools.runAsync(e.project, "Initializing Document Extractor", true) { progress -> + try { + progress.text = "Setting up session..." + val session = Session.newGlobalID() + DataStorage.sessionPaths[session] = selectedFile.toFile.parentFile + progress.text = "Configuring AI model..." + val smartModel = AppSettingsState.instance.smartModel.chatModel() + val parsingModel = ParsingModelType.getImpl(smartModel, 0.1, modelType) + progress.text = "Initializing document parser..." + SessionProxyServer.metadataStorage.setSessionName( + null, session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + val app = object : DocumentParserApp( + applicationName = "Document Extractor", + path = this@DocumentDataExtractorAction.path, + api = this@DocumentDataExtractorAction.api, + fileInputs = processableFiles.map { it.toNioPath() }, + parsingModel = parsingModel as ParsingModel, + fastMode = settings.fastMode, + ) { + override fun initSettings(session: Session): T = this@DocumentDataExtractorAction.settings as T + override val root: File get() = selectedFile.parent.toFile + } + SessionProxyServer.chats[session] = app + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Document Data Extractor", singleInput = false, stickyInput = true, loadImages = false, showMenubar = false + ) + progress.text = "Starting server..." + val server = AppServer.getServer(e.project) + launchBrowser(server, session.toString()) + } catch (ex: Throwable) { + log.error("Failed to initialize document extractor", ex) + UITools.showErrorDialog( + "Failed to initialize document extractor: ${ex.message}", "Initialization Error" + ) + } + } + } + + private fun launchBrowser(server: AppServer, session: String) { + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + companion object { + private val log = LoggerFactory.getLogger(DocumentDataExtractorAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/knowledge/DocumentDataExtractorConfigDialog.kt b/src/main/kotlin/aicoder/actions/knowledge/DocumentDataExtractorConfigDialog.kt new file mode 100644 index 00000000..60195bf5 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/knowledge/DocumentDataExtractorConfigDialog.kt @@ -0,0 +1,141 @@ +package aicoder.actions.knowledge + +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.ui.ValidationInfo +import com.intellij.ui.dsl.builder.bindItem +import com.intellij.ui.dsl.builder.bindSelected +import com.intellij.ui.dsl.builder.bindText +import com.intellij.ui.dsl.builder.panel +import com.simiacryptus.skyenet.apps.parse.DocumentParserApp +import com.simiacryptus.skyenet.apps.parse.ParsingModelType +import javax.swing.JComponent + +class DocumentDataExtractorConfigDialog( + project: Project?, + var settings: DocumentParserApp.Settings, + var modelType: ParsingModelType<*> +) : DialogWrapper(project, true) { + companion object { + private const val DEFAULT_DPI = 300f + private const val DEFAULT_MAX_PAGES = 100 + private const val DEFAULT_PAGES_PER_BATCH = 10 + } + + private var dpiValue = settings.dpi.toString() + private var maxPagesValue = settings.maxPages.toString() + private var outputFormatValue = settings.outputFormat + private var pagesPerBatchValue = settings.pagesPerBatch.toString() + private var showImagesValue = settings.showImages + private var saveImageFilesValue = settings.saveImageFiles + private var saveTextFilesValue = settings.saveTextFiles + private var saveFinalJsonValue = settings.saveFinalJson + private var fastModeValue = settings.fastMode + private var addLineNumbersValue = settings.addLineNumbers + private var selectedModelType = modelType + + init { + init() + title = "Configure Document Data Extractor" + } + + override fun createCenterPanel(): JComponent { + return panel { + row("Parsing Model:") { + comboBox(ParsingModelType.values().toList()) + .bindItem({ selectedModelType }, { selectedModelType = it ?: modelType }) + } + row("DPI:") { + textField() + .bindText({ dpiValue }, { dpiValue = it }) + .validationOnInput { + validateFloatField(it.text, "DPI") + } + } + row("Max Pages:") { + textField() + .bindText({ maxPagesValue }, { maxPagesValue = it }) + .validationOnInput { + validateIntField(it.text, "Max pages") + } + } + row("Output Format:") { + textField() + .bindText({ outputFormatValue }, { outputFormatValue = it }) + } + row("Pages Per Batch:") { + textField() + .bindText({ pagesPerBatchValue }, { pagesPerBatchValue = it }) + .validationOnInput { + validateIntField(it.text, "Pages per batch") + } + } + row { + checkBox("Show Images") + .bindSelected({ showImagesValue }, { showImagesValue = it }) + checkBox("Save Image Files") + .bindSelected({ saveImageFilesValue }, { saveImageFilesValue = it }) + } + row { + checkBox("Save Text Files") + .bindSelected({ saveTextFilesValue }, { saveTextFilesValue = it }) + checkBox("Save Final JSON") + .bindSelected({ saveFinalJsonValue }, { saveFinalJsonValue = it }) + } + row { + checkBox("Fast Mode") + .bindSelected({ fastModeValue }, { fastModeValue = it }) + checkBox("Add Line Numbers") + .bindSelected({ addLineNumbersValue }, { addLineNumbersValue = it }) + } + } + } + + private fun validateFloatField(text: String, fieldName: String): ValidationInfo? { + try { + text.toFloat().also { + if (it <= 0) return ValidationInfo("$fieldName must be positive") + } + } catch (e: NumberFormatException) { + return ValidationInfo("Invalid $fieldName value") + } + return null + } + + private fun validateIntField(text: String, fieldName: String): ValidationInfo? { + try { + text.toInt().also { + if (it <= 0) return ValidationInfo("$fieldName must be positive") + } + } catch (e: NumberFormatException) { + return ValidationInfo("Invalid $fieldName value") + } + return null + } + + override fun doValidate(): ValidationInfo? { + return validateFloatField(dpiValue, "DPI") + ?: validateIntField(maxPagesValue, "Max pages") + ?: validateIntField(pagesPerBatchValue, "Pages per batch") + } + + + override fun doOKAction() { + if (doValidate() != null) return + + settings = DocumentParserApp.Settings( + dpi = dpiValue.toFloatOrNull() ?: DEFAULT_DPI, + maxPages = maxPagesValue.toIntOrNull() ?: DEFAULT_MAX_PAGES, + outputFormat = outputFormatValue, + pagesPerBatch = pagesPerBatchValue.toIntOrNull() ?: DEFAULT_PAGES_PER_BATCH, + showImages = showImagesValue, + saveImageFiles = saveImageFilesValue, + saveTextFiles = saveTextFilesValue, + saveFinalJson = saveFinalJsonValue, + fastMode = fastModeValue, + addLineNumbers = addLineNumbersValue + ) + modelType = selectedModelType + super.doOKAction() + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/knowledge/SaveAsQueryIndexAction.kt b/src/main/kotlin/aicoder/actions/knowledge/SaveAsQueryIndexAction.kt new file mode 100644 index 00000000..3c18a9c8 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/knowledge/SaveAsQueryIndexAction.kt @@ -0,0 +1,104 @@ +package aicoder.actions.knowledge + +import aicoder.actions.BaseAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.progress.Task +import com.simiacryptus.aicoder.util.IdeaOpenAIClient +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.aicoder.util.findRecursively +import com.simiacryptus.skyenet.apps.parse.DocumentRecord.Companion.saveAsBinary +import com.simiacryptus.skyenet.apps.parse.ProgressState +import org.slf4j.LoggerFactory +import java.util.concurrent.Executors + +class SaveAsQueryIndexAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + data class IndexConfig( + val threadCount: Int = 8, + val batchSize: Int = 100 + ) + + private fun getConfig(project: com.intellij.openapi.project.Project?): IndexConfig { + // Could be enhanced to show a dialog for configuration + return IndexConfig() + } + + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + val selectedFiles = UITools.getSelectedFiles(event) + return selectedFiles.isNotEmpty() && selectedFiles.any { file -> + file.isDirectory || file.name.endsWith(".parsed.json") + } + } + + + override fun handle(e: AnActionEvent) { + val selectedFiles = UITools.getSelectedFiles(e) + if (selectedFiles.isEmpty()) { + UITools.showErrorDialog( + "Please select JSON files to convert.", + "No Files Selected" + ) + return + } + val jsonFiles = selectedFiles.flatMap { file -> + when { + file.isDirectory -> file.findRecursively { it.name.endsWith(".parsed.json") } + file.name.endsWith(".parsed.json") -> listOf(file) + else -> emptyList() + } + } + if (jsonFiles.isEmpty()) { + UITools.showErrorDialog("No .parsed.json files found in selection.", "No Valid Files") + return + } + val config = getConfig(e.project) + ProgressManager.getInstance().run(object : Task.Backgroundable(e.project, "Indexing Vectors", true) { + override fun run(indicator: ProgressIndicator) { + val threadPool = Executors.newFixedThreadPool(config.threadCount) + try { + indicator.isIndeterminate = false + indicator.fraction = 0.0 + indicator.text = "Initializing vector indexing..." + + saveAsBinary( + openAIClient = IdeaOpenAIClient.instance, + pool = threadPool, + progressState = ProgressState().apply { + onUpdate += { + indicator.fraction = it.progress / it.max + indicator.text = "Processing files (${it.progress}/${it.max})" + if (indicator.isCanceled) { + throw InterruptedException("Operation cancelled by user") + } + } + }, + inputPaths = jsonFiles.map { it.path }.toTypedArray() + ) + + indicator.fraction = 1.0 + indicator.text = "Vector indexing complete" + log.info("Conversion to Data complete") + UITools.showInfoMessage("Vector indexing completed successfully", "Success") + } catch (ex: InterruptedException) { + log.info("Vector indexing cancelled by user") + UITools.showInfoMessage("Vector indexing cancelled", "Cancelled") + } catch (ex: Exception) { + log.error("Error during binary conversion", ex) + UITools.showErrorDialog("Error during conversion: ${ex.message}", "Conversion Failed") + } finally { + threadPool.shutdownNow() + } + } + }) + } + + + companion object { + private val log = LoggerFactory.getLogger(SaveAsQueryIndexAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/legacy/AppendTextWithChatAction.kt b/src/main/kotlin/aicoder/actions/legacy/AppendTextWithChatAction.kt new file mode 100644 index 00000000..d2f2db09 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/legacy/AppendTextWithChatAction.kt @@ -0,0 +1,54 @@ +package aicoder.actions.legacy + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.ApiModel.* +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.util.ClientUtil.toContentList + +/** + * Action that appends AI-generated text to the current selection. + * Uses ChatGPT to generate contextually relevant continuations of the selected text. + * + * @see SelectionAction + */ + +class AppendTextWithChatAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions + + override fun getConfig(project: Project?): String { + return "" + } + + override fun processSelection(state: SelectionState, config: String?, progress: ProgressIndicator): String { + try { + val settings = AppSettingsState.instance + val request = ChatRequest( + model = settings.smartModel, + temperature = settings.temperature + ).copy( + temperature = settings.temperature, + messages = listOf( + ChatMessage(Role.system, "Append text to the end of the user's prompt".toContentList(), null), + ChatMessage(Role.user, state.selectedText.toString().toContentList(), null) + ), + ) + val chatResponse = api.chat(request, settings.smartModel.chatModel()) + val originalText = state.selectedText ?: "" + val generatedText = chatResponse.choices[0].message?.content ?: "" + // Remove duplicate text if AI response includes the original text + return originalText + if (generatedText.startsWith(originalText)) + generatedText.substring(originalText.length) else generatedText + } catch (e: Exception) { + UITools.error(log, "Failed to generate text continuation", e) + return state.selectedText ?: "" + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/legacy/CommentsAction.kt b/src/main/kotlin/aicoder/actions/legacy/CommentsAction.kt new file mode 100644 index 00000000..501cd3f3 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/legacy/CommentsAction.kt @@ -0,0 +1,62 @@ +package aicoder.actions.legacy + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy + +class CommentsAction : SelectionAction() { + private val log = Logger.getInstance(CommentsAction::class.java) + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!super.isEnabled(event)) return false + return AppSettingsState.instance.enableLegacyActions + } + + override fun getConfig(project: Project?): String { + return "" + } + + override fun processSelection(state: SelectionState, config: String?, progress: ProgressIndicator): String { + try { + val selectedText = state.selectedText ?: return "" + val language = state.language?.toString() ?: state.editor?.virtualFile?.extension ?: return selectedText + return ChatProxy( + clazz = CommentsAction_VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ).create().editCode( + selectedText, + "Add comments to each line explaining the code", + language, + AppSettingsState.instance.humanLanguage + ).code ?: selectedText + } catch (e: Exception) { + log.error("Failed to process comments", e) + throw e + } + } + + interface CommentsAction_VirtualAPI { + fun editCode( + code: String, + operations: String, + computerLanguage: String, + humanLanguage: String + ): CommentsAction_ConvertedText + + class CommentsAction_ConvertedText { + var code: String? = null + var language: String? = null + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/legacy/DocAction.kt b/src/main/kotlin/aicoder/actions/legacy/DocAction.kt new file mode 100644 index 00000000..027dad23 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/legacy/DocAction.kt @@ -0,0 +1,115 @@ +package aicoder.actions.legacy + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.aicoder.util.IndentedText +import com.simiacryptus.aicoder.util.psi.PsiUtil +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy + +/** + * Action that generates documentation for selected code blocks. + * Supports multiple programming languages and documentation styles. + */ + +class DocAction : SelectionAction() { + companion object { + private const val DEFAULT_DESERIALIZER_RETRIES = 5 + } + + private val log = com.intellij.openapi.diagnostic.Logger.getInstance(DocAction::class.java) + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions + + interface DocAction_VirtualAPI { + fun processCode( + code: String, + operation: String, + computerLanguage: String, + humanLanguage: String + ): DocAction_ConvertedText + + class DocAction_ConvertedText { + var text: String? = null + var language: String? = null + } + } + + private val proxy: DocAction_VirtualAPI by lazy { + val chatProxy = ChatProxy( + clazz = DocAction_VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = DEFAULT_DESERIALIZER_RETRIES + ) + chatProxy.addExample( + DocAction_VirtualAPI.DocAction_ConvertedText().apply { + text = """ + /** + * Prints "Hello, world!" to the console + */ + """.trimIndent() + language = "English" + } + ) { + it.processCode( + """ + fun hello() { + println("Hello, world!") + } + """.trimIndent(), + "Write detailed KDoc prefix for code block", + "Kotlin", + "English" + ) + } + chatProxy.create() + } + + override fun getConfig(project: Project?): String { + return "" + } + + override fun processSelection(state: SelectionState, config: String?, progress: ProgressIndicator): String { + try { + val code = state.selectedText ?: return "" + val indentedInput = IndentedText.fromString(code) + val docString = proxy.processCode( + indentedInput.textBlock.toString(), + "Write detailed " + (state.language?.docStyle ?: "documentation") + " prefix for code block", + state.language?.name ?: "", + AppSettingsState.instance.humanLanguage + ).text ?: "" + return docString + code + } catch (e: Exception) { + log.error("Failed to generate documentation", e) + throw RuntimeException( + "Failed to generate documentation: ${e.message}", + e + ) + } + + } + + override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { + if (computerLanguage == ComputerLanguage.Text) return false + if (computerLanguage?.docStyle == null) return false + if (computerLanguage.docStyle.isBlank()) return false + return true + } + + override fun editSelection(state: EditorState, start: Int, end: Int): Pair { + if (state.psiFile == null) return super.editSelection(state, start, end) + val codeBlock = PsiUtil.getCodeElement(state.psiFile, start, end) + if (codeBlock == null) return super.editSelection(state, start, end) + val textRange = codeBlock.textRange + return Pair(textRange.startOffset, textRange.endOffset) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/legacy/ImplementStubAction.kt b/src/main/kotlin/aicoder/actions/legacy/ImplementStubAction.kt new file mode 100644 index 00000000..cbd3f69e --- /dev/null +++ b/src/main/kotlin/aicoder/actions/legacy/ImplementStubAction.kt @@ -0,0 +1,113 @@ +package aicoder.actions.legacy + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.aicoder.util.psi.PsiUtil +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy +import com.simiacryptus.util.StringUtil +import java.util.* + +/** + * Action that implements stub methods/classes using AI code generation. + * Extends SelectionAction to handle code selection and language detection. + */ + +class ImplementStubAction : SelectionAction() { + private val log = Logger.getInstance(ImplementStubAction::class.java) + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions + + interface VirtualAPI { + fun editCode( + code: String, + operation: String, + computerLanguage: String, + humanLanguage: String + ): ConvertedText + + class ConvertedText { + var code: String? = null + var language: String? = null + } + } + + private fun getProxy(): VirtualAPI { + return ChatProxy( + clazz = VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ).create() + } + + override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { + if (computerLanguage == null) return false + return computerLanguage != ComputerLanguage.Text + } + + override fun defaultSelection(editorState: EditorState, offset: Int): Pair { + val codeRanges = editorState.contextRanges.filter { PsiUtil.matchesType(it.name, PsiUtil.ELEMENTS_CODE) } + if (codeRanges.isEmpty()) return editorState.line + return codeRanges.minByOrNull { it.length() }?.range() ?: editorState.line + } + + override fun getConfig(project: Project?): String { + return "" + } + + override fun processSelection(state: SelectionState, config: String?, progress: ProgressIndicator): String { + try { + val code = state.selectedText ?: "" + val settings = AppSettingsState.instance + val outputHumanLanguage = settings.humanLanguage + val computerLanguage = state.language ?: return code + if (!isLanguageSupported(computerLanguage)) { + UITools.showWarning(null, "Language ${computerLanguage.name} is not supported") + return code + } + return processCode(code = code, state = state, computerLanguage = computerLanguage, outputHumanLanguage = outputHumanLanguage, progress = progress) + } catch (e: Exception) { + log.error("Error implementing stub", e) + UITools.showError(null, "Failed to implement stub: ${e.message}") + return state.selectedText ?: "" + } + } + + private fun processCode( + code: String, + state: SelectionState, + computerLanguage: ComputerLanguage, + outputHumanLanguage: String, + progress: ProgressIndicator + ): String { + + val codeContext = state.contextRanges.filter { + PsiUtil.matchesType(it.name, PsiUtil.ELEMENTS_CODE) + } + var smallestIntersectingMethod = "" + if (codeContext.isNotEmpty()) smallestIntersectingMethod = + codeContext.minByOrNull { it.length() }?.subString(state.entireDocument ?: "") ?: "" + + var declaration = code + declaration = StringUtil.stripSuffix(declaration.trim(), smallestIntersectingMethod) + declaration = declaration.trim() + + return getProxy().editCode( + declaration, + "Implement Stub", + computerLanguage.name.lowercase(Locale.ROOT), + outputHumanLanguage + ).code ?: "" + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/legacy/InsertImplementationAction.kt b/src/main/kotlin/aicoder/actions/legacy/InsertImplementationAction.kt new file mode 100644 index 00000000..d3d559bb --- /dev/null +++ b/src/main/kotlin/aicoder/actions/legacy/InsertImplementationAction.kt @@ -0,0 +1,153 @@ +package aicoder.actions.legacy + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.aicoder.util.TextBlock +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.aicoder.util.psi.PsiClassContext +import com.simiacryptus.aicoder.util.psi.PsiUtil +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy + +class InsertImplementationAction : SelectionAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions + + interface VirtualAPI { + fun implementCode( + specification: String, + prefix: String, + computerLanguage: String, + humanLanguage: String + ): ConvertedText + + class ConvertedText { + var code: String? = null + var language: String? = null + } + } + + private fun getProxy(): VirtualAPI { + return ChatProxy( + clazz = VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ).create() + } + + override fun getConfig(project: Project?): String { + try { + // Validate settings before proceeding + if (AppSettingsState.instance.smartModel == null) { + UITools.showErrorDialog("AI model not configured", "Configuration Error") + return "" + } + return "" + } catch (e: Exception) { + UITools.error(log, "Failed to get configuration", e) + return "" + } + } + + override fun defaultSelection(editorState: EditorState, offset: Int): Pair { + val foundItem = editorState.contextRanges.filter { + PsiUtil.matchesType( + it.name, + PsiUtil.ELEMENTS_COMMENTS + ) + }.minByOrNull { it.length() } + return foundItem?.range() ?: editorState.line + } + + override fun editSelection(state: EditorState, start: Int, end: Int): Pair { + val foundItem = state.contextRanges.filter { + PsiUtil.matchesType( + it.name, + PsiUtil.ELEMENTS_COMMENTS + ) + }.minByOrNull { it.length() } + return foundItem?.range() ?: Pair(start, end) + } + + override fun processSelection(state: SelectionState, config: String?, progress: ProgressIndicator): String { + val humanLanguage: String = AppSettingsState.instance.humanLanguage + val computerLanguage: ComputerLanguage? = state.language + try { + val psiClassContextActionParams = getPsiClassContextActionParams(state) + val selectedText = state.selectedText ?: "" + + val comment = psiClassContextActionParams.largestIntersectingComment + var instruct = comment?.subString(state.entireDocument ?: "")?.trim() ?: selectedText + if (selectedText.split(" ").dropWhile { it.isEmpty() }.size > 4) { + instruct = selectedText.trim() + } + val fromString: TextBlock? = computerLanguage?.getCommentModel(instruct)?.fromString(instruct) + val specification = fromString?.rawString()?.map { it.toString().trim() } + ?.filter { it.isNotEmpty() }?.reduce { a, b -> "$a $b" } ?: return selectedText + val code = if (state.psiFile != null) { + progress.isIndeterminate = false + progress.text = "Analyzing context..." + progress.fraction = 0.2 + val psiClassContext = runReadAction { + PsiClassContext.getContext( + state.psiFile, + psiClassContextActionParams.selectionStart, + psiClassContextActionParams.selectionEnd, + computerLanguage + ).toString() + } + progress.text = "Generating implementation..." + progress.fraction = 0.6 + getProxy().implementCode( + specification = specification, + prefix = psiClassContext, + computerLanguage = computerLanguage.name, + humanLanguage = humanLanguage + ).code ?: throw IllegalStateException("No code generated") + } else { + getProxy().implementCode(specification, "", computerLanguage.name, humanLanguage).code + } + getProxy().implementCode( + specification, + "", + computerLanguage.name, + humanLanguage + ).code + return if (code != null) "$selectedText\n${state.indent}$code" else selectedText + } catch (e: Exception) { + UITools.error(log, "Failed to process selection", e) + return state.selectedText ?: "" + } + } + + private fun getPsiClassContextActionParams(state: SelectionState): PsiClassContextActionParams { + val selectionStart = state.selectionOffset + return PsiClassContextActionParams( + selectionStart, + selectionStart + (state.selectionLength ?: 0), + state.contextRanges.find { PsiUtil.matchesType(it.name, PsiUtil.ELEMENTS_COMMENTS) } + ) + } + + override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { + if (computerLanguage == null || computerLanguage == ComputerLanguage.Text || computerLanguage == ComputerLanguage.Markdown) { + return false + } + return super.isLanguageSupported(computerLanguage) + } + + private class PsiClassContextActionParams( + val selectionStart: Int, + val selectionEnd: Int, + val largestIntersectingComment: ContextRange? + ) +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/legacy/OpenWebPageAction.kt b/src/main/kotlin/aicoder/actions/legacy/OpenWebPageAction.kt new file mode 100644 index 00000000..b9f9bfc3 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/legacy/OpenWebPageAction.kt @@ -0,0 +1,13 @@ +package aicoder.actions.legacy + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import java.net.URI + +class OpenWebPageAction : AnAction() { + override fun actionPerformed(event: AnActionEvent) { + browse(URI("http://apps.simiacrypt.us/")) + } + +} diff --git a/src/main/kotlin/aicoder/actions/legacy/RenameVariablesAction.kt b/src/main/kotlin/aicoder/actions/legacy/RenameVariablesAction.kt new file mode 100644 index 00000000..5cfcfd59 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/legacy/RenameVariablesAction.kt @@ -0,0 +1,102 @@ +package aicoder.actions.legacy + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy + +/** + * Action to suggest and apply variable name improvements in code. + * Supports multiple programming languages and uses AI to generate naming suggestions. + */ + +open class RenameVariablesAction : SelectionAction() { + private val log = Logger.getInstance(RenameVariablesAction::class.java) + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions + + interface RenameAPI { + fun suggestRenames( + code: String, + computerLanguage: String, + humanLanguage: String + ): SuggestionResponse + + class SuggestionResponse { + var suggestions: MutableList = mutableListOf() + + class Suggestion { + var originalName: String? = null + var suggestedName: String? = null + } + } + } + + val proxy: RenameAPI + get() { + return ChatProxy( + clazz = RenameAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ).create() + } + + override fun getConfig(project: Project?): String { + return "" + } + + @Throws(Exception::class) + override fun processSelection(event: AnActionEvent?, state: SelectionState, config: String?): String { + try { + val renameSuggestions = UITools.run(event?.project, "Analyzing Code", true, true) { progress -> + progress.text = "Generating rename suggestions..." + proxy + .suggestRenames( + state.selectedText ?: "", + state.language?.name ?: state.editor?.virtualFile?.extension ?: "", + AppSettingsState.instance.humanLanguage + ) + .suggestions + .filter { it.originalName != null && it.suggestedName != null } + .associate { it.originalName!! to it.suggestedName!! } + } + if (renameSuggestions.isEmpty()) { + UITools.showInfoMessage("No rename suggestions found", "No Changes") + return state.selectedText ?: "" + } + val selectedSuggestions = Companion.choose(renameSuggestions) + return UITools.run(event?.project, "Applying Changes", true, true) { progress -> + progress.text = "Applying selected renames..." + var selectedText = state.selectedText + val filter = renameSuggestions.filter { it.key in selectedSuggestions } + filter.forEach { (key, value) -> + selectedText = selectedText?.replace(key, value) + } + selectedText ?: "" + } + } catch (e: Exception) { + log.error("Error during rename operation", e) + UITools.showErrorDialog("Failed to process rename operation: ${e.message}", "Error") + throw e + } + } + + companion object { + fun choose(renameSuggestions: Map): Set { + return UITools.showCheckboxDialog( + "Select which items to rename", + renameSuggestions.keys.toTypedArray(), + renameSuggestions.map { (key, value) -> "$key -> $value" }.toTypedArray() + ).toSet() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/legacy/ReplaceWithSuggestionsAction.kt b/src/main/kotlin/aicoder/actions/legacy/ReplaceWithSuggestionsAction.kt new file mode 100644 index 00000000..17bbef9f --- /dev/null +++ b/src/main/kotlin/aicoder/actions/legacy/ReplaceWithSuggestionsAction.kt @@ -0,0 +1,87 @@ +package aicoder.actions.legacy + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy +import com.simiacryptus.util.StringUtil +import kotlin.math.ceil +import kotlin.math.ln +import kotlin.math.pow + +open class ReplaceWithSuggestionsAction : SelectionAction() { + private val log = Logger.getInstance(ReplaceWithSuggestionsAction::class.java) + private val templateText = "Generating suggestions..." + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions + + interface VirtualAPI { + fun suggestText(template: String, examples: List): Suggestions + + class Suggestions { + var choices: List? = null + } + } + + val proxy: VirtualAPI + get() { + return ChatProxy( + clazz = VirtualAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ).create() + } + + override fun getConfig(project: Project?): String { + // Could be enhanced to get user preferences for suggestion generation + return "" + } + + override fun processSelection(event: AnActionEvent?, state: SelectionState, config: String?): String { + try { + val choices: List = UITools.run(event?.project, templateText, true, true) { progress -> + progress.isIndeterminate = false + progress.text = "Analyzing context..." + progress.fraction = 0.2 + val selectedText = state.selectedText ?: return@run emptyList() + val idealLength = 2.0.pow(2 + ceil(ln(selectedText.length.toDouble()))).toInt() + progress.text = "Preparing context..." + progress.fraction = 0.4 + val selectionStart = state.selectionOffset + val allBefore = state.entireDocument?.substring(0, selectionStart) ?: "" + val selectionEnd = state.selectionOffset + (state.selectionLength ?: 0) + val allAfter = state.entireDocument?.substring(selectionEnd, state.entireDocument.length) ?: "" + val before = StringUtil.getSuffixForContext(allBefore, idealLength).toString().replace('\n', ' ') + val after = StringUtil.getPrefixForContext(allAfter, idealLength).toString().replace('\n', ' ') + progress.text = "Generating suggestions..." + progress.fraction = 0.6 + proxy.suggestText( + "$before _____ $after", + listOf(selectedText) + ).choices ?: emptyList() + } + return choose(choices) + } catch (e: Exception) { + log.error("Failed to generate suggestions", e) + UITools.showErrorDialog( + "Failed to generate suggestions: ${e.message}", + "Error" + ) + return state.selectedText ?: "" + } + } + + open fun choose(choices: List): String { + return UITools.showRadioButtonDialog("Select an option to fill in the blank:", *choices.toTypedArray()) + ?.toString() ?: "" + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/legacy/VoiceToTextAction.kt b/src/main/kotlin/aicoder/actions/legacy/VoiceToTextAction.kt new file mode 100644 index 00000000..cac32597 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/legacy/VoiceToTextAction.kt @@ -0,0 +1,136 @@ +package aicoder.actions.legacy + +import aicoder.actions.BaseAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.command.WriteCommandAction +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.audio.AudioRecorder +import com.simiacryptus.jopenai.audio.LookbackLoudnessWindowBuffer +import org.slf4j.LoggerFactory +import java.util.* +import java.util.concurrent.ConcurrentLinkedDeque +import java.util.concurrent.Executors +import java.util.concurrent.Future +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicInteger +import javax.sound.sampled.AudioSystem +import javax.sound.sampled.TargetDataLine +import javax.swing.JFrame +import javax.swing.JLabel + +class VoiceToTextAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + val continueFn = statusDialog(e)::isVisible + + val rawBuffer = ConcurrentLinkedDeque() + Thread({ + try { + log.warn("Recording thread started") + AudioRecorder(rawBuffer, 0.05, continueFn).run() + log.warn("Recording thread complete") + } catch (e: Throwable) { + UITools.error(log, "Error", e) + } + }, "dication-audio-recorder").start() + + val wavBuffer = ConcurrentLinkedDeque() + Thread({ + log.warn("Audio processing thread started") + try { + LookbackLoudnessWindowBuffer(rawBuffer, wavBuffer, continueFn).run() + } catch (e: Throwable) { + UITools.error(log, "Error", e) + } + log.warn("Audio processing thread complete") + }, "dictation-audio-processor").start() + + val caretModel = (e.getData(CommonDataKeys.EDITOR) ?: return).caretModel + val primaryCaret = caretModel.primaryCaret + val dictationPump = if (primaryCaret.hasSelection()) { + DictationPump(e, wavBuffer, continueFn, primaryCaret.selectionEnd, primaryCaret.selectedText ?: "") + } else { + DictationPump(e, wavBuffer, continueFn, caretModel.offset) + } + Thread({ + log.warn("Speech-To-Text thread started") + try { + dictationPump.run() + } catch (e: Throwable) { + UITools.error(log, "Error", e) + } + log.warn("Speech-To-Text thread complete") + }, "dictation-api-processor").start() + } + + private inner class DictationPump( + val event: AnActionEvent, + private val audioBuffer: Deque, + val continueFn: () -> Boolean, + offsetStart: Int, + var prompt: String = "" + ) { + + private val offset: AtomicInteger = AtomicInteger(offsetStart) + + fun run() { + while (this.continueFn() || audioBuffer.isNotEmpty()) { + val recordAudio = audioBuffer.poll() + if (null == recordAudio) { + Thread.sleep(1) + } else { + log.warn("Speech-To-Text Starting...") + var text = api2.transcription(recordAudio, prompt) + if (prompt.isNotEmpty()) text = " $text" + val newPrompt = (prompt + text).split(" ").takeLast(32).joinToString(" ") + log.warn("Speech-To-Text Complete\n Prompt: $prompt\n Result: $text") + prompt = newPrompt + WriteCommandAction.runWriteCommandAction(event.project) { + val editor = event.getData(CommonDataKeys.EDITOR) ?: return@runWriteCommandAction + editor.document.insertString(offset.getAndAdd(text.length), text) + } + } + } + } + } + + + private fun statusDialog(e1: AnActionEvent): JFrame { + val dialog = JFrame("Dictation") + val jLabel = JLabel("Close this window to stop recording and dictation") + jLabel.font = jLabel.font.deriveFont(48f) + dialog.add(jLabel) + dialog.pack() + dialog.location = e1.getData(PlatformDataKeys.CONTEXT_COMPONENT)?.locationOnScreen!! + dialog.isAlwaysOnTop = true + dialog.isVisible = true + return dialog + } + + override fun isEnabled(event: AnActionEvent): Boolean { + if (!AppSettingsState.instance.enableLegacyActions) return false + return try { + null != targetDataLine.get(50, TimeUnit.MILLISECONDS) + } catch (e: Exception) { + false + } + } + + companion object { + private val log = LoggerFactory.getLogger(VoiceToTextAction::class.java) + + private val pool = Executors.newFixedThreadPool(1) + + val targetDataLine: Future by lazy { + pool.submit { + AudioSystem.getTargetDataLine(AudioRecorder.audioFormat) + } + } + } + +} diff --git a/src/main/kotlin/aicoder/actions/markdown/MarkdownImplementActionGroup.kt b/src/main/kotlin/aicoder/actions/markdown/MarkdownImplementActionGroup.kt new file mode 100644 index 00000000..41f3d3e6 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/markdown/MarkdownImplementActionGroup.kt @@ -0,0 +1,95 @@ +package aicoder.actions.markdown + +import aicoder.actions.SelectionAction +import com.intellij.openapi.actionSystem.ActionGroup +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.ComputerLanguage +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy +import org.slf4j.LoggerFactory + +class MarkdownImplementActionGroup : ActionGroup() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + private val markdownLanguages = listOf( + "sql", "java", "asp", "c", "clojure", "coffee", "cpp", "csharp", "css", "bash", "go", "java", "javascript", + "less", "make", "matlab", "objectivec", "pascal", "PHP", "Perl", "python", "rust", "scss", "sql", "svg", + "swift", "ruby", "smalltalk", "vhdl" + ) + + override fun update(e: AnActionEvent) { + e.presentation.isEnabledAndVisible = isEnabled(e) + super.update(e) + } + + companion object { + private val log = LoggerFactory.getLogger(MarkdownImplementActionGroup::class.java) + fun isEnabled(e: AnActionEvent): Boolean { + return try { + val computerLanguage = ComputerLanguage.getComputerLanguage(e) ?: return false + ComputerLanguage.Markdown == computerLanguage && UITools.hasSelection(e) + } catch (ex: Exception) { + log.error("Error checking action enablement", ex) + false + } + } + } + + override fun getChildren(e: AnActionEvent?): Array { + if (e == null) return emptyArray() + val computerLanguage = ComputerLanguage.getComputerLanguage(e) ?: return emptyArray() + val actions = markdownLanguages.map { language -> MarkdownImplementAction(language) } + return actions.toTypedArray() + } + + open class MarkdownImplementAction(private val language: String) : SelectionAction(true) { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + init { + templatePresentation.text = language + templatePresentation.description = language + } + + interface ConversionAPI { + fun implement(text: String, humanLanguage: String, computerLanguage: String): ConvertedText + + class ConvertedText { + var code: String? = null + var language: String? = null + } + } + + private fun getProxy(): ConversionAPI { + return ChatProxy( + clazz = ConversionAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ).create() + } + + override fun getConfig(project: Project?): String { + return "" + } + + override fun processSelection(state: SelectionState, config: String?, progress: ProgressIndicator): String { + return try { + progress.text = "Generating $language code..." + progress.isIndeterminate = true + val code = getProxy().implement(state.selectedText ?: "", "autodetect", language).code + ?: throw IllegalStateException("No code generated") + "\n\n```$language\n${code.trim()}\n```\n" + } catch (e: Exception) { + log.error("Error processing selection", e) + UITools.showErrorDialog("Failed to convert code: ${e.message}", "Conversion Error") + state.selectedText ?: "" + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/markdown/MarkdownListAction.kt b/src/main/kotlin/aicoder/actions/markdown/MarkdownListAction.kt new file mode 100644 index 00000000..5cacc388 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/markdown/MarkdownListAction.kt @@ -0,0 +1,161 @@ +package aicoder.actions.markdown + +import aicoder.actions.BaseAction +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.aicoder.util.UITools.getIndent +import com.simiacryptus.aicoder.util.UITools.insertString +import com.simiacryptus.aicoder.util.psi.PsiUtil.getAll +import com.simiacryptus.aicoder.util.psi.PsiUtil.getSmallestIntersecting +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.proxy.ChatProxy +import com.simiacryptus.util.StringUtil +import java.awt.Component +import javax.swing.JOptionPane + +/** + * Action that extends markdown lists by generating additional items using AI. + * Supports bullet lists and checkbox lists. + */ +class MarkdownListAction : BaseAction() { + private val log = Logger.getInstance(MarkdownListAction::class.java) + private lateinit var progress: ProgressIndicator + + data class ListConfig( + val itemCount: Int = 0, + val temperature: Double = AppSettingsState.instance.temperature + ) + + /** + * Gets configuration for list generation + */ + private fun getConfig(project: Project?): ListConfig? { + return try { + ListConfig( + itemCount = UITools.showInputDialog( + project as? Component, + "How many new items to generate?", + "Generate List Items", + JOptionPane.QUESTION_MESSAGE + )?.let { Integer.parseInt(it.toString()) } ?: return null + ) + } catch (e: Exception) { + log.warn("Failed to get configuration", e) + null + } + } + + override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT + + interface ListAPI { + fun newListItems( + items: List?, + count: Int, + ): Items + + data class Items( + val items: List? = null, + ) + } + + val proxy: ListAPI + get() { + val chatProxy = ChatProxy( + clazz = ListAPI::class.java, + api = api, + model = AppSettingsState.instance.smartModel.chatModel(), + temperature = AppSettingsState.instance.temperature, + deserializerRetries = 5 + ) + chatProxy.addExample( + returnValue = ListAPI.Items( + items = listOf("Item 4", "Item 5", "Item 6") + ) + ) { + it.newListItems( + items = listOf("Item 1", "Item 2", "Item 3"), + count = 6 + ) + } + return chatProxy.create() + } + + override fun handle(e: AnActionEvent) { + try { + val caret = e.getData(CommonDataKeys.CARET) ?: return + val psiFile = e.getData(CommonDataKeys.PSI_FILE) ?: return + val project = e.project ?: return + val config = getConfig(project) ?: return + val list = + getSmallestIntersecting(psiFile, caret.selectionStart, caret.selectionEnd, "MarkdownListImpl") ?: return + val items = StringUtil.trim( + getAll(list, "MarkdownListItemImpl") + .map { + val all = getAll(it, "MarkdownParagraphImpl") + if (all.isEmpty()) it.text else all[0].text + }.toList(), 10, false + ) + progress.fraction = 0.4 + progress.text = "Generating new items..." + val indent = getIndent(caret) + val endOffset = list.textRange.endOffset + val bulletTypes = listOf("- [ ] ", "- ", "* ") + val document = (e.getData(CommonDataKeys.EDITOR) ?: return).document + val rawItems = items.map(CharSequence::trim).map { + val bulletType = bulletTypes.find(it::startsWith) + if (null != bulletType) StringUtil.stripPrefix(it, bulletType).toString() + else it.toString() + } + + UITools.redoableTask(e) { + var newItems: List? = null + progress.isIndeterminate = false + progress.fraction = 0.2 + progress.text = "Analyzing existing items..." + UITools.run( + e.project, "Generating New Items", true + ) { + newItems = proxy.newListItems( + rawItems, + config.itemCount + ).items + progress.fraction = 0.8 + progress.text = "Formatting results..." + } + var newList = "" + ApplicationManager.getApplication().runReadAction { + val strippedList = list.text.split("\n") + .map(String::trim).filter(String::isNotEmpty) + .joinToString("\n") + val bulletString = bulletTypes.find(strippedList::startsWith) ?: "1. " + newList = newItems?.joinToString("\n") { indent.toString() + bulletString + it } ?: "" + } + UITools.writeableFn(e) { + insertString(document, endOffset, "\n" + newList) + } + } + + } catch (ex: Exception) { + log.error("Failed to generate list items", ex) + UITools.showErrorDialog( + "Failed to generate list items: ${ex.message}", + "Error" + ) + } + } + + override fun isEnabled(e: AnActionEvent): Boolean { + val caret = e.getData(CommonDataKeys.CARET) ?: return false + val psiFile = e.getData(CommonDataKeys.PSI_FILE) ?: return false + getSmallestIntersecting(psiFile, caret.selectionStart, caret.selectionEnd, "MarkdownListImpl") ?: return false + return super.isEnabled(e) + } + +} diff --git a/src/main/kotlin/aicoder/actions/plan/AutoPlanChatAction.kt b/src/main/kotlin/aicoder/actions/plan/AutoPlanChatAction.kt new file mode 100644 index 00000000..b847b44f --- /dev/null +++ b/src/main/kotlin/aicoder/actions/plan/AutoPlanChatAction.kt @@ -0,0 +1,163 @@ +package aicoder.actions.plan + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.SimpleCommandAction.Companion.tripleTilde +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.apps.general.AutoPlanChatApp +import com.simiacryptus.skyenet.apps.plan.PlanSettings +import com.simiacryptus.skyenet.apps.plan.PlanUtil.isWindows +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.file.DataStorage +import com.simiacryptus.skyenet.core.util.FileValidationUtils +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import java.io.File +import java.nio.file.Path +import java.text.SimpleDateFormat + +class AutoPlanChatAction : BaseAction() { + // Maximum file size to process (512KB) + private companion object { + private const val MAX_FILE_SIZE = 512 * 1024 + } + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + val dialog = PlanConfigDialog( + e.project, PlanSettings( + defaultModel = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + shellCmd = listOf( + if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + ), + temperature = AppSettingsState.instance.temperature.coerceIn(0.0, 1.0), + workingDir = UITools.getRoot(e), + env = mapOf(), + githubToken = AppSettingsState.instance.githubToken, + googleApiKey = AppSettingsState.instance.googleApiKey, + googleSearchEngineId = AppSettingsState.instance.googleSearchEngineId, + ) + ) + if (dialog.showAndGet()) { + try { + val planSettings = dialog.settings + UITools.runAsync(e.project, "Initializing Auto Plan Chat", true) { progress -> + initializeChat(e, progress, planSettings) + } + } catch (ex: Exception) { + log.error("Failed to initialize chat", ex) + UITools.showError(e.project, "Failed to initialize chat: ${ex.message}") + } + } + } + + private fun initializeChat(e: AnActionEvent, progress: ProgressIndicator, planSettings: PlanSettings) { + progress.text = "Setting up session..." + val session = Session.newGlobalID() + val root = getProjectRoot(e) ?: throw RuntimeException("Could not determine project root") + progress.text = "Processing files..." + setupChatSession(session, root, e, planSettings) + progress.text = "Starting server..." + val server = AppServer.getServer(e.project) + openBrowser(server, session.toString()) + } + + private fun getProjectRoot(e: AnActionEvent): File? { + val folder = UITools.getSelectedFolder(e) + return folder?.toFile ?: UITools.getSelectedFile(e)?.parent?.toFile?.let { file -> + getModuleRootForFile(file) + } + } + + private fun setupChatSession(session: Session, root: File, e: AnActionEvent, planSettings: PlanSettings) { + DataStorage.sessionPaths[session] = root + SessionProxyServer.chats[session] = createChatApp(root, e, planSettings) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Auto Plan Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + } + + private fun createChatApp(root: File, e: AnActionEvent, planSettings: PlanSettings): AutoPlanChatApp = object : AutoPlanChatApp( + planSettings = planSettings.copy( + env = mapOf(), + workingDir = root.absolutePath, + language = if (isWindows) "powershell" else "bash", + command = listOf( + if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + ), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + ), + model = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + showMenubar = false, + api = api, + api2 = api2, + ) { + private fun codeFiles() = (UITools.getSelectedFiles(e).toTypedArray().toList().flatMap { + FileValidationUtils.expandFileList(it.toFile).toList() + }.map { it.toPath() }.toSet()?.toMutableSet() ?: mutableSetOf()) + .filter { it.toFile().exists() } + .filter { it.toFile().length() < MAX_FILE_SIZE } + .map { root.toPath().relativize(it) ?: it }.toSet() + + private fun codeSummary() = codeFiles() + .joinToString("\n\n") { path -> + "# ${path}\n$tripleTilde${path.toString().split('.').lastOrNull()}\n${root.resolve(path.toFile()).readText(Charsets.UTF_8)}\n$tripleTilde" + } + + private fun projectSummary() = codeFiles() + .asSequence().distinct().sorted() + .joinToString("\n") { path -> + "* ${path} - ${root.resolve(path.toFile()).length()} bytes" + } + + override fun contextData(): List = + try { + listOf( + if (codeFiles().size < 4) { + "Files:\n" + codeSummary() + } else { + "Files:\n" + projectSummary() + } + ) + } catch (e: Exception) { + log.error("Error generating context data", e) + emptyList() + } + } + + private fun openBrowser(server: AppServer, session: String) { + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/plan/PlanAheadAction.kt b/src/main/kotlin/aicoder/actions/plan/PlanAheadAction.kt new file mode 100644 index 00000000..1a4b120d --- /dev/null +++ b/src/main/kotlin/aicoder/actions/plan/PlanAheadAction.kt @@ -0,0 +1,100 @@ +package aicoder.actions.plan + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.apps.general.PlanAheadApp +import com.simiacryptus.skyenet.apps.plan.PlanSettings +import com.simiacryptus.skyenet.apps.plan.PlanUtil.isWindows +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.file.DataStorage +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import kotlin.collections.set + + +class PlanAheadAction : BaseAction() { + val path = "/taskDev" + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + val dialog = PlanConfigDialog( + e.project, PlanSettings( + defaultModel = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + shellCmd = listOf( + if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + ), + temperature = AppSettingsState.instance.temperature, + workingDir = UITools.getRoot(e), + env = mapOf(), + githubToken = AppSettingsState.instance.githubToken, + googleApiKey = AppSettingsState.instance.googleApiKey, + googleSearchEngineId = AppSettingsState.instance.googleSearchEngineId, + ) + ) + if (dialog.showAndGet()) { + // Settings are applied only if the user clicks OK + val session = Session.newGlobalID() + val folder = UITools.getSelectedFolder(e) + val root = folder?.toFile ?: getModuleRootForFile( + UITools.getSelectedFile(e)?.parent?.toFile ?: throw RuntimeException("") + ) + DataStorage.sessionPaths[session] = root + val planSettings = dialog.settings.copy( + env = mapOf(), + workingDir = root.absolutePath, + language = if (isWindows) "powershell" else "bash", + command = listOf( + if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + ), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + ) + SessionProxyServer.chats[session] = PlanAheadApp( + planSettings = planSettings, + model = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + showMenubar = false, + api = api, + api2 = api2, + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + val server = AppServer.getServer(e.project) + + openBrowser(server, session.toString()) + } + } + + private fun openBrowser(server: AppServer, session: String) { + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + LoggerFactory.getLogger(PlanAheadAction::class.java).warn("Error opening browser", e) + } + }.start() + } + + companion object { + private val log = LoggerFactory.getLogger(PlanAheadAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/plan/PlanChatAction.kt b/src/main/kotlin/aicoder/actions/plan/PlanChatAction.kt new file mode 100644 index 00000000..de5e9979 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/plan/PlanChatAction.kt @@ -0,0 +1,126 @@ +package aicoder.actions.plan + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.command.WriteCommandAction +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.apps.general.PlanChatApp +import com.simiacryptus.skyenet.apps.plan.PlanSettings +import com.simiacryptus.skyenet.apps.plan.PlanUtil.isWindows +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.file.DataStorage +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import org.slf4j.LoggerFactory +import kotlin.collections.set + +/** + * Action that opens a Plan Chat interface for executing and planning commands. + * Supports both Windows (PowerShell) and Unix (Bash) environments. + */ + +class PlanChatAction : BaseAction() { + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + override fun isEnabled(e: AnActionEvent): Boolean { + if (!super.isEnabled(e)) return false + return UITools.getSelectedFolder(e) != null || UITools.getSelectedFile(e) != null + } + + + override fun handle(e: AnActionEvent) { + try { + UITools.runAsync(e.project, "Initializing Plan Chat", true) { progress -> + progress.isIndeterminate = true + progress.text = "Setting up chat environment..." + initializeAndOpenChat(e) + } + } catch (ex: Throwable) { + UITools.error(log, "Failed to initialize Plan Chat", ex) + } + } + + private fun initializeAndOpenChat(e: AnActionEvent) { + val dialog = PlanConfigDialog( + e.project, PlanSettings( + defaultModel = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + shellCmd = listOf( + if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + ), + temperature = AppSettingsState.instance.temperature, + workingDir = UITools.getRoot(e), + env = mapOf(), + githubToken = AppSettingsState.instance.githubToken, + googleApiKey = AppSettingsState.instance.googleApiKey, + googleSearchEngineId = AppSettingsState.instance.googleSearchEngineId, + ) + ) + if (dialog.showAndGet()) { + setupChatSession(e, dialog.settings) + } + } + + private fun setupChatSession(e: AnActionEvent, settings: PlanSettings) { + WriteCommandAction.runWriteCommandAction(e.project) { + val session = Session.newGlobalID() + val folder = UITools.getSelectedFolder(e) + val root = folder?.toFile ?: getModuleRootForFile( + UITools.getSelectedFile(e)?.parent?.toFile ?: throw RuntimeException("") + ) + DataStorage.sessionPaths[session] = root + SessionProxyServer.chats[session] = PlanChatApp( + planSettings = settings.copy( + env = mapOf(), + workingDir = root.absolutePath, + language = if (isWindows) "powershell" else "bash", + command = listOf( + if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + ), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + ), + model = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + showMenubar = false, + api = api, + api2 = api2, + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + val server = AppServer.getServer(e.project) + openBrowser(server, session.toString()) + } + } + + private fun openBrowser(server: AppServer, session: String) { + ApplicationManager.getApplication().invokeLater { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.error("Failed to open browser", e) + LoggerFactory.getLogger(PlanChatAction::class.java).warn("Error opening browser", e) + } + } + } + + companion object { + private val log = LoggerFactory.getLogger(PlanChatAction::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/plan/PlanConfigDialog.kt b/src/main/kotlin/aicoder/actions/plan/PlanConfigDialog.kt new file mode 100644 index 00000000..b137742e --- /dev/null +++ b/src/main/kotlin/aicoder/actions/plan/PlanConfigDialog.kt @@ -0,0 +1,530 @@ +package aicoder.actions.plan + +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.ComboBox +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.ui.JBSplitter +import com.intellij.ui.components.JBList +import com.intellij.ui.components.JBScrollPane +import com.intellij.ui.dsl.builder.Align +import com.intellij.ui.dsl.builder.RowLayout +import com.intellij.ui.dsl.builder.panel +import com.intellij.ui.table.JBTable +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.skyenet.apps.plan.PlanSettings +import com.simiacryptus.skyenet.apps.plan.TaskSettingsBase +import com.simiacryptus.skyenet.apps.plan.TaskType +import com.simiacryptus.skyenet.apps.plan.tools.CommandAutoFixTask +import java.awt.CardLayout +import java.awt.Component +import java.awt.Dimension +import java.awt.Font +import javax.swing.* +import javax.swing.table.DefaultTableModel + +class PlanConfigDialog( + project: Project?, + val settings: PlanSettings, + val singleTaskMode: Boolean = false, +) : DialogWrapper(project) { + companion object { + private const val CONFIG_COMBO_WIDTH = 200 + private const val CONFIG_COMBO_HEIGHT = 30 + private const val MIN_TEMP = 0 + private const val MAX_TEMP = 100 + private const val DEFAULT_LIST_WIDTH = 150 + private const val DEFAULT_LIST_HEIGHT = 200 + private const val DEFAULT_PANEL_WIDTH = 350 + private const val DEFAULT_PANEL_HEIGHT = 200 + private const val TEMPERATURE_SCALE = 100.0 + private const val TEMPERATURE_LABEL = "%.2f" + private const val FONT_SIZE_ENABLED = 14f + private const val FONT_SIZE_DISABLED = 12f + private const val DIVIDER_PROPORTION = 0.3f + + fun isVisible(it: ChatModel): Boolean { + return AppSettingsState.instance.apiKey?.get(it.provider.name)?.isNotBlank() ?: false + } + } + + private fun validateModelSelection(taskType: TaskType<*, *>, model: ChatModel?): Boolean { + if (model == null && settings.getTaskSettings(taskType).enabled) { + JOptionPane.showMessageDialog( + null, "Please select a model for enabled task: ${taskType.name}", "Model Required", JOptionPane.WARNING_MESSAGE + ) + return false + } + return true + } + + private fun validateConfigName(name: String?) = when { + name.isNullOrBlank() -> { + JOptionPane.showMessageDialog( + null, "Please enter a valid configuration name", "Invalid Name", JOptionPane.WARNING_MESSAGE + ) + false + } + + name.contains(Regex("[^a-zA-Z0-9_-]")) -> { + JOptionPane.showMessageDialog( + null, "Configuration name can only contain letters, numbers, underscores and hyphens", "Invalid Name", JOptionPane.WARNING_MESSAGE + ) + false + } + + else -> true + } + + private inner class TaskTypeListCellRenderer : DefaultListCellRenderer() { + private fun getTaskTooltip(taskType: TaskType<*, *>): String = """ + + +

${taskType.name}

+

${taskType.tooltipHtml}

+ + + """ + + override fun getListCellRendererComponent( + list: JList<*>?, value: Any?, index: Int, isSelected: Boolean, cellHasFocus: Boolean + ): Component { + val component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus) + if (component is JLabel && value is TaskType<*, *>) { + toolTipText = getTaskTooltip(value) + val isEnabled = settings.getTaskSettings(value).enabled + font = when (isEnabled) { + + true -> font.deriveFont(Font.BOLD + Font.PLAIN, FONT_SIZE_ENABLED) + false -> font.deriveFont(Font.ITALIC + Font.PLAIN, FONT_SIZE_DISABLED) + } + foreground = if (isEnabled) { + list?.foreground + } else { + list?.foreground?.darker()?.darker() + } + text = buildString { + val taskDescription = value.description ?: "" + append(value.name) + if (taskDescription.isNotEmpty()) { + append(" - ") + append(taskDescription) + } + } + } + return component + } + } + + private inner class TaskTypeConfigPanel(val taskType: TaskType<*, *>) : JPanel() { + val enabledCheckbox = JCheckBox("Enabled", settings.getTaskSettings(taskType).enabled) + val modelComboBox = ComboBox(getVisibleModels().distinctBy { it.modelName }.map { it.modelName }.toTypedArray()).apply { + maximumSize = Dimension(DEFAULT_PANEL_WIDTH - 50, 30) + preferredSize = Dimension(DEFAULT_PANEL_WIDTH - 50, 30) + if (itemCount > 0) { + val currentModel = settings.getTaskSettings(taskType).model + selectedItem = when { + currentModel != null -> currentModel.modelName + else -> defaultModel + } + } + } + private val commandList = if (taskType == TaskType.CommandAutoFix) { + JBTable(object : DefaultTableModel( + arrayOf("Enabled", "Command"), 0 + ) { + + private val entries = mutableListOf() + + init { + val sortedExecutables = AppSettingsState.instance.executables.sortedWith(String.CASE_INSENSITIVE_ORDER) + sortedExecutables.forEach { command -> + val isEnabled = + (settings.getTaskSettings(taskType) as? CommandAutoFixTask.CommandAutoFixTaskSettings)?.commandAutoFixCommands?.contains(command) ?: true + entries.add(CommandTableEntry(isEnabled, command)) + addRow(arrayOf(isEnabled, command)) + } + } + + override fun getColumnClass(columnIndex: Int) = when (columnIndex) { + 0 -> java.lang.Boolean::class.java + else -> super.getColumnClass(columnIndex) + } + + override fun isCellEditable(row: Int, column: Int) = column == 0 + + override fun setValueAt(aValue: Any?, row: Int, column: Int) { + if (column == 0 && aValue is Boolean) { + entries[row].enabled = aValue + super.setValueAt(aValue, row, column) + fireTableCellUpdated(row, column) + updateCommandSettings() + taskTypeList.repaint() + } else { + throw IllegalArgumentException("Invalid column index: $column") + } + } + + private fun updateCommandSettings() { + val newSettings = CommandAutoFixTask.CommandAutoFixTaskSettings( + taskType.name, + settings.getTaskSettings(taskType).enabled, + getVisibleModels().find { it.modelName == modelComboBox.selectedItem }, + entries.filter { it.enabled }.map { it.command }) + settings.setTaskSettings(taskType, newSettings) + } + }).apply { + preferredScrollableViewportSize = Dimension(DEFAULT_PANEL_WIDTH - 50, 100) + columnModel.getColumn(0).apply { + preferredWidth = 50 + maxWidth = 100 + cellEditor = DefaultCellEditor(JCheckBox()) + headerValue = "Enable/disable
command" + } + columnModel.getColumn(1).apply { + headerValue = "Command path
or name" + } + } + } else null + + init { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + alignmentX = Component.LEFT_ALIGNMENT + border = BorderFactory.createEmptyBorder(5, 5, 5, 5) + add(enabledCheckbox.apply { alignmentX = Component.LEFT_ALIGNMENT }) + add(Box.createVerticalStrut(5)) + add(JLabel("Model:").apply { alignmentX = Component.LEFT_ALIGNMENT }) + add(Box.createVerticalStrut(2)) + add(modelComboBox.apply { alignmentX = Component.LEFT_ALIGNMENT }) + if (commandList != null) { + add(Box.createVerticalStrut(10)) + add(JLabel("Available Commands:").apply { alignmentX = Component.LEFT_ALIGNMENT }) + add(Box.createVerticalStrut(2)) + add(JBScrollPane(commandList).apply { + alignmentX = Component.LEFT_ALIGNMENT + preferredSize = Dimension(DEFAULT_PANEL_WIDTH - 50, DEFAULT_LIST_HEIGHT / 2) + maximumSize = Dimension(DEFAULT_PANEL_WIDTH - 50, DEFAULT_LIST_HEIGHT / 2) + }) + add(Box.createVerticalStrut(5)) + add(JPanel().apply { + layout = BoxLayout(this, BoxLayout.X_AXIS) + alignmentX = Component.LEFT_ALIGNMENT + maximumSize = Dimension(DEFAULT_PANEL_WIDTH - 50, 30) + add(JButton("Add Command").apply { + maximumSize = Dimension(DEFAULT_PANEL_WIDTH / 2 - 30, 30) + addActionListener { + val command = JOptionPane.showInputDialog( + this, "Enter command path:", "Add Command", JOptionPane.PLAIN_MESSAGE + ) + if (command != null && command.isNotEmpty()) { + (commandList.model as DefaultTableModel).addRow(arrayOf(true, command)) + AppSettingsState.instance.executables.add(command) + } + } + }) + add(Box.createHorizontalStrut(5)) + add(JButton("Remove Command").apply { + maximumSize = Dimension(DEFAULT_PANEL_WIDTH / 2 - 30, 30) + addActionListener { + val selectedRow = commandList.selectedRow + if (selectedRow != -1) { + val command = (commandList.model as DefaultTableModel).getValueAt(selectedRow, 1) as String + val confirmResult = JOptionPane.showConfirmDialog( + null, "Remove command: $command?", "Confirm Remove", JOptionPane.YES_NO_OPTION + ) + if (confirmResult == JOptionPane.YES_OPTION) { + (commandList.model as DefaultTableModel).removeRow(selectedRow) + AppSettingsState.instance.executables.remove(command) + } + } else { + JOptionPane.showMessageDialog( + null, "Please select a command to remove." + ) + } + } + }) + }) + } + + val currentModel = settings.getTaskSettings(taskType).model + modelComboBox.selectedItem = currentModel?.modelName ?: defaultModel + enabledCheckbox.addItemListener { + val newSettings = when (taskType) { + TaskType.CommandAutoFix -> CommandAutoFixTask.CommandAutoFixTaskSettings( + taskType.name, + enabledCheckbox.isSelected, + getVisibleModels().find { it.modelName == modelComboBox.selectedItem }, + (0 until (commandList?.model?.rowCount ?: 0)).filter { row -> (commandList?.model?.getValueAt(row, 0) as? Boolean) ?: false } + .map { row -> commandList?.model?.getValueAt(row, 1) as String }) + + else -> TaskSettingsBase(taskType.name, enabledCheckbox.isSelected).apply { + this.model = getVisibleModels().find { it.modelName == modelComboBox.selectedItem } + } + } + settings.setTaskSettings(taskType, newSettings) + taskTypeList.repaint() + } + modelComboBox.addActionListener { + val newSettings = when (taskType) { + TaskType.CommandAutoFix -> CommandAutoFixTask.CommandAutoFixTaskSettings( + taskType.name, + enabledCheckbox.isSelected, + getVisibleModels().find { it.modelName == modelComboBox.selectedItem }, + (0 until (commandList?.model?.rowCount ?: 0)).map { row -> + commandList?.model?.getValueAt(row, 1) as String + }) + + else -> TaskSettingsBase(taskType.name, enabledCheckbox.isSelected).apply { + this.model = getVisibleModels().find { it.modelName == modelComboBox.selectedItem } + } + } + settings.setTaskSettings(taskType, newSettings) + } + } + + fun saveSettings() { + val newSettings = when (taskType) { + TaskType.CommandAutoFix -> CommandAutoFixTask.CommandAutoFixTaskSettings( + task_type = taskType.name, + enabled = enabledCheckbox.isSelected, + model = getVisibleModels().find { it.modelName == modelComboBox.selectedItem }, + commandAutoFixCommands = (0 until (commandList?.model?.rowCount ?: 0)).filter { row -> + commandList?.model?.getValueAt(row, 0) as Boolean + }.map { row -> commandList?.model?.getValueAt(row, 1) as String }) + + else -> TaskSettingsBase(taskType.name, enabledCheckbox.isSelected).apply { + this.model = getVisibleModels().find { it.modelName == modelComboBox.selectedItem } + } + } + if (validateModelSelection(taskType, newSettings.model)) { + settings.setTaskSettings(taskType, newSettings) + } + } + } + + private data class CommandTableEntry( + var enabled: Boolean, val command: String + ) + + private val temperatureSlider = JSlider(MIN_TEMP, MAX_TEMP, (settings.temperature * TEMPERATURE_SCALE).toInt()).apply { + addChangeListener { + settings.temperature = value / TEMPERATURE_SCALE + temperatureLabel.text = TEMPERATURE_LABEL.format(settings.temperature) + } + } + private val defaultModel = AppSettingsState.instance.smartModel + private val fastModel = AppSettingsState.instance.fastModel + private val temperatureLabel = JLabel(TEMPERATURE_LABEL.format(settings.temperature)) + private val autoFixCheckbox = JCheckBox("Auto-apply fixes", settings.autoFix) + private val allowBlockingCheckbox = JCheckBox("Allow blocking", settings.allowBlocking) + private val taskTypeList = JBList(TaskType.values()) + private val configPanelContainer = JPanel(CardLayout()) + private val taskConfigs = mutableMapOf() + private val savedConfigsCombo = ComboBox().apply { + preferredSize = Dimension(CONFIG_COMBO_WIDTH, CONFIG_COMBO_HEIGHT) + AppSettingsState.instance.savedPlanConfigs.keys.sorted().forEach { addItem(it) } + } + + private fun getVisibleModels() = ChatModel.values().map { it.value }.filter { isVisible(it) }.toList().sortedBy { "${it.provider.name} - ${it.modelName}" } + + init { + taskTypeList.cellRenderer = TaskTypeListCellRenderer() + taskTypeList.addListSelectionListener { e -> + if (!e.valueIsAdjusting) { + val selectedType = (taskTypeList.selectedValue as TaskType<*, *>).name + (configPanelContainer.layout as CardLayout).show(configPanelContainer, selectedType) + if (singleTaskMode) { + TaskType.values().forEach { taskType -> + val isSelected = taskType.name == selectedType + taskConfigs[taskType.name]?.enabledCheckbox?.isSelected = isSelected + } + } + } + } + TaskType.values().forEach { taskType -> + val configPanel = TaskTypeConfigPanel(taskType) + taskConfigs[taskType.name] = configPanel + configPanelContainer.add(configPanel, taskType.name) + } + taskTypeList.selectedIndex = 0 + init() + title = "Configure Planning and Tasks" + temperatureSlider.addChangeListener { + settings.temperature = temperatureSlider.value / 100.0 + } + } + + + private fun saveCurrentConfig() { + val configName = JOptionPane.showInputDialog( + null, "Enter configuration name:", "Save Configuration", JOptionPane.PLAIN_MESSAGE + )?.trim() + + if (!validateConfigName(configName)) { + return + } + taskConfigs.values.forEach { it.saveSettings() } + if (AppSettingsState.instance.savedPlanConfigs.containsKey(configName)) { + val confirmResult = JOptionPane.showConfirmDialog( + null, "Configuration '$configName' already exists. Overwrite?", "Confirm Overwrite", JOptionPane.YES_NO_OPTION + ) + if (confirmResult != JOptionPane.YES_OPTION) { + return + } + } + val taskSettingsMap = TaskType.values().associate { taskType -> + val taskSettings = settings.getTaskSettings(taskType) + taskType.name to TaskSettingsBase( + task_type = taskType.name, + enabled = taskSettings.enabled, + model = taskSettings.model, + ) + } + val config = AppSettingsState.SavedPlanConfig( + name = configName!!, + temperature = settings.temperature, + autoFix = settings.autoFix, + allowBlocking = settings.allowBlocking, + taskSettings = taskSettingsMap + ) + AppSettingsState.instance.savedPlanConfigs[configName] = config + savedConfigsCombo.addItem(configName) + savedConfigsCombo.selectedItem = configName + } + + private fun loadConfig(configName: String) { + val config = AppSettingsState.instance.savedPlanConfigs[configName] ?: return + val hasUnsavedChanges = TaskType.values().any { taskType -> + val currentSettings = settings.getTaskSettings(taskType) + val savedSettings = config.taskSettings[taskType.name] + currentSettings.enabled != savedSettings?.enabled || currentSettings.model?.modelName != savedSettings.model?.modelName + } + if (hasUnsavedChanges) { + val confirmResult = JOptionPane.showConfirmDialog( + null, "Loading will discard unsaved changes. Continue?", "Confirm Load", JOptionPane.YES_NO_OPTION + ) + if (confirmResult != JOptionPane.YES_OPTION) { + return + } + } + try { + val validatedTemp = config.temperature.coerceIn(0.0, 1.0) + settings.temperature = validatedTemp + temperatureSlider.value = (validatedTemp * TEMPERATURE_SCALE).toInt() + temperatureLabel.text = TEMPERATURE_LABEL.format(validatedTemp) + settings.autoFix = config.autoFix + settings.allowBlocking = config.allowBlocking + autoFixCheckbox.isSelected = config.autoFix + allowBlockingCheckbox.isSelected = config.allowBlocking + config.taskSettings.forEach { (taskTypeName: String, serializedSettings: TaskSettingsBase) -> + val taskType = TaskType.values().find { it.name == taskTypeName } ?: return@forEach + val availableModels = getVisibleModels() + val selectedModel = availableModels.find { it.modelName == serializedSettings.model?.modelName } ?: availableModels.firstOrNull() + settings.setTaskSettings(taskType, serializedSettings) + taskConfigs[taskType.name]?.apply { + enabledCheckbox.isSelected = serializedSettings.enabled + if (modelComboBox.itemCount > 0 && selectedModel != null) { + modelComboBox.selectedItem = selectedModel.modelName + } else { + modelComboBox.selectedItem = defaultModel + } + } + } + // Update UI once after all changes + taskTypeList.repaint() + } catch (e: Exception) { + JOptionPane.showMessageDialog( + null, "Error loading configuration: ${e.message}", "Load Error", JOptionPane.ERROR_MESSAGE + ) + } + } + + override fun createCenterPanel(): JComponent = panel { + group("Settings") { + if (!singleTaskMode) { + row("Saved Configs:") { + cell(savedConfigsCombo).align(Align.FILL).comment("Select a saved configuration to load or save current settings") + button("Save...") { + saveCurrentConfig() + } + button("Load") { + val selected = savedConfigsCombo.selectedItem as? String + if (selected != null) { + loadConfig(selected) + } else { + JOptionPane.showMessageDialog( + null, "Please select a configuration to load", "No Configuration Selected", JOptionPane.WARNING_MESSAGE + ) + } + } + button("Delete") { + val selected = savedConfigsCombo.selectedItem as? String + if (selected != null) { + val confirmResult = JOptionPane.showConfirmDialog( + null, "Delete configuration '$selected'?", "Confirm Delete", JOptionPane.YES_NO_OPTION + ) + if (confirmResult == JOptionPane.YES_OPTION) { + AppSettingsState.instance.savedPlanConfigs.remove(selected) + savedConfigsCombo.removeItem(selected) + } + } else { + JOptionPane.showMessageDialog( + null, "Please select a configuration to delete", "No Configuration Selected", JOptionPane.WARNING_MESSAGE + ) + } + } + } + } + row { + cell(autoFixCheckbox).align(Align.FILL).comment("Automatically apply suggested fixes without confirmation") + } + row { + cell(allowBlockingCheckbox).align(Align.FILL).comment("Allow tasks to block UI while processing") + } + row("Temperature:") { + cell(temperatureSlider).align(Align.FILL).comment("Adjust AI response creativity (higher = more creative)") + cell(temperatureLabel) + } + } + group("Tasks") { + row { + cell( + JBSplitter(false, DIVIDER_PROPORTION).apply { + firstComponent = JBScrollPane(taskTypeList).apply { + minimumSize = Dimension(DEFAULT_LIST_WIDTH, DEFAULT_LIST_HEIGHT) + preferredSize = Dimension(DEFAULT_LIST_WIDTH + 100, DEFAULT_LIST_HEIGHT) + } + secondComponent = JBScrollPane(configPanelContainer).apply { + minimumSize = Dimension(DEFAULT_PANEL_WIDTH, DEFAULT_PANEL_HEIGHT / 2) + preferredSize = Dimension(DEFAULT_PANEL_WIDTH, DEFAULT_PANEL_HEIGHT) + } + dividerWidth = 3 + isShowDividerControls = true + isShowDividerIcon = true + }).align(Align.FILL).resizableColumn() + }.resizableRow() + }.layout(RowLayout.PARENT_GRID).resizableRow() + } + + override fun doOKAction() { + val invalidTasks = taskConfigs.values.filter { configPanel -> + val isEnabled = configPanel.enabledCheckbox.isSelected + val model = getVisibleModels().find { it.modelName == configPanel.modelComboBox.selectedItem } + isEnabled && model == null + } + if (invalidTasks.isNotEmpty()) { + val taskNames = invalidTasks.map { it.taskType.name }.joinToString(", ") + JOptionPane.showMessageDialog( + null, "Please select models for enabled tasks: $taskNames", "Missing Models", JOptionPane.WARNING_MESSAGE + ) + return + } + taskConfigs.values.forEach { configPanel -> + configPanel.saveSettings() + } + settings.autoFix = autoFixCheckbox.isSelected + settings.allowBlocking = allowBlockingCheckbox.isSelected + super.doOKAction() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/plan/PrePlanAction.kt b/src/main/kotlin/aicoder/actions/plan/PrePlanAction.kt new file mode 100644 index 00000000..b9dd385d --- /dev/null +++ b/src/main/kotlin/aicoder/actions/plan/PrePlanAction.kt @@ -0,0 +1,162 @@ +package aicoder.actions.plan + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.ui.Messages +import com.intellij.ui.components.JBLabel +import com.intellij.ui.components.JBTextField +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.apps.general.PlanAheadApp +import com.simiacryptus.skyenet.apps.plan.PlanSettings +import com.simiacryptus.skyenet.apps.plan.PlanUtil.isWindows +import com.simiacryptus.skyenet.apps.plan.TaskBreakdownWithPrompt +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.file.DataStorage +import com.simiacryptus.skyenet.core.util.getModuleRootForFile +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.util.JsonUtil +import org.slf4j.LoggerFactory +import java.awt.GridBagConstraints +import java.awt.GridBagLayout +import javax.swing.JComponent +import javax.swing.JPanel + +class PrePlanAction : BaseAction() { + val path = "/prePlanTaskDev" + + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + var jsonInput = Messages.showMultilineInputDialog( + e.project, + "Enter TaskBreakdownWithPrompt JSON:", + "Pre-Plan Task", + "", + Messages.getQuestionIcon(), + null, + ) ?: return + jsonInput = fillInTemplate(jsonInput) + + try { + val taskBreakdownWithPrompt = JsonUtil.fromJson(jsonInput, TaskBreakdownWithPrompt::class.java) + + val session = Session.newGlobalID() + val folder = UITools.getSelectedFolder(e) + val root = folder?.toFile ?: getModuleRootForFile( + UITools.getSelectedFile(e)?.parent?.toFile ?: throw RuntimeException("No file selected") + ) + DataStorage.sessionPaths[session] = root + + var planSettings = PlanSettings( + defaultModel = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + shellCmd = listOf( + if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + ), + temperature = AppSettingsState.instance.temperature, + workingDir = UITools.getRoot(e), + env = mapOf(), + language = if (isWindows) "powershell" else "bash", + githubToken = AppSettingsState.instance.githubToken, + googleApiKey = AppSettingsState.instance.googleApiKey, + googleSearchEngineId = AppSettingsState.instance.googleSearchEngineId, + ) + planSettings = PlanConfigDialog(e.project, planSettings).let { + if (!it.showAndGet()) throw RuntimeException("User cancelled") + it.settings + } + SessionProxyServer.Companion.chats[session] = PlanAheadApp( + planSettings = planSettings, + model = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + showMenubar = false, + initialPlan = taskBreakdownWithPrompt, + api = api, + api2 = api2, + ) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + + val server = AppServer.getServer(e.project) + openBrowser(server, session.toString()) + } catch (ex: Exception) { + Messages.showErrorDialog(e.project, "Invalid JSON input: ${ex.message}", "Error") + } + } + + private fun openBrowser(server: AppServer, session: String) { + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + companion object { + private val log = LoggerFactory.getLogger(PrePlanAction::class.java) + + fun fillInTemplate(jsonInput: String): String { + val variables = Regex("\\{\\{(\\w+)}}").findAll(jsonInput).map { it.groupValues[1] }.toSet() + if (variables.isEmpty()) return jsonInput + val formValues = showFormDialog(variables) + return variables.fold(jsonInput) { acc, variable -> + acc.replace("{{$variable}}", formValues[variable] ?: "") + } + } + + private fun showFormDialog(variables: Set): Map { + val dialog = object : DialogWrapper(true) { + val fields = variables.associateWith { JBTextField() } + + init { + init() + title = "Fill in Template Variables" + } + + override fun createCenterPanel(): JComponent { + val panel = JPanel(GridBagLayout()) + val gbc = GridBagConstraints().apply { + fill = GridBagConstraints.HORIZONTAL + weightx = 1.0 + } + variables.forEach { variable -> + gbc.gridy++ + gbc.gridx = 0 + panel.add(JBLabel(variable), gbc) + gbc.gridx = 1 + panel.add(fields[variable], gbc) + } + return panel + } + + fun getValues(): Map { + return fields.mapValues { (_, field) -> field.text } + } + } + return if (dialog.showAndGet()) { + dialog.getValues() + } else { + mapOf() + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/plan/SingleTaskAction.kt b/src/main/kotlin/aicoder/actions/plan/SingleTaskAction.kt new file mode 100644 index 00000000..8f33a3d7 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/plan/SingleTaskAction.kt @@ -0,0 +1,170 @@ +package aicoder.actions.plan + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.progress.ProgressIndicator +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.jopenai.util.GPT4Tokenizer +import com.simiacryptus.skyenet.apps.general.SingleTaskApp +import com.simiacryptus.skyenet.apps.plan.PlanSettings +import com.simiacryptus.skyenet.apps.plan.PlanUtil.isWindows +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.file.DataStorage +import com.simiacryptus.skyenet.core.util.FileValidationUtils +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import java.io.File +import java.text.SimpleDateFormat + +class SingleTaskAction : BaseAction() { + override fun getActionUpdateThread() = ActionUpdateThread.BGT + + override fun handle(e: AnActionEvent) { + val dialog = PlanConfigDialog( + e.project, + PlanSettings( + defaultModel = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + shellCmd = listOf( + if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + ), + temperature = AppSettingsState.instance.temperature.coerceIn(0.0, 1.0), + workingDir = UITools.getRoot(e), + env = mapOf(), + githubToken = AppSettingsState.instance.githubToken, + googleApiKey = AppSettingsState.instance.googleApiKey, + googleSearchEngineId = AppSettingsState.instance.googleSearchEngineId, + ), + singleTaskMode = true + ) + if (dialog.showAndGet()) { + try { + val planSettings = dialog.settings + UITools.runAsync(e.project, "Initializing Single Task", true) { progress -> + initializeTask(e, progress, planSettings, contextData(e)) + } + } catch (ex: Exception) { + log.error("Failed to initialize task", ex) + UITools.showError(e.project, "Failed to initialize task: ${ex.message}") + } + } + } + + private fun initializeTask( + e: AnActionEvent, + progress: ProgressIndicator, + planSettings: PlanSettings, + contextData: List = emptyList(), + ) { + progress.text = "Setting up session..." + val session = Session.newGlobalID() + val root = getProjectRoot(e) + progress.text = "Processing files..." + setupTaskSession(session, root, planSettings, contextData) + progress.text = "Starting server..." + val server = AppServer.getServer(e.project) + openBrowser(server, session.toString()) + } + + private fun getProjectRoot(e: AnActionEvent) = + UITools.getSelectedFolder(e)?.toFile ?: UITools.getRoot(e).let { File(it) } + + private fun setupTaskSession( + session: Session, + root: File, + planSettings: PlanSettings, + contextData: List = emptyList(), + ) { + DataStorage.sessionPaths[session] = root + SessionProxyServer.chats[session] = createSingleTaskApp(root, planSettings, contextData) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Single Task", + singleInput = true, + stickyInput = false, + loadImages = false, + showMenubar = false + ) + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + } + + private fun createSingleTaskApp( + root: File, + planSettings: PlanSettings, + contextData: List = emptyList(), + ): SingleTaskApp = object : SingleTaskApp( + applicationName = "Single Task", + planSettings = planSettings.copy( + env = mapOf(), + workingDir = root.absolutePath, + language = if (isWindows) "powershell" else "bash", + command = listOf( + if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + ), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + ), + model = AppSettingsState.instance.smartModel.chatModel(), + parsingModel = AppSettingsState.instance.fastModel.chatModel(), + showMenubar = false, + api = api, + api2 = api2, + ) { + override fun contextData(): List { + return contextData + } + } + + private fun openBrowser(server: AppServer, session: String) { + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + companion object { + fun contextData(event: AnActionEvent): List { + val selectedFiles = UITools.getSelectedFiles(event).toTypedArray().toList() + if (selectedFiles.isEmpty()) return emptyList() + val root = File(UITools.getRoot(event)) + return selectedFiles + .flatMap { virtualFile -> + try { + FileValidationUtils.expandFileList(virtualFile.toFile).toList() + } catch (e: Exception) { + emptyList() + } + } + .filter { file -> + file.exists() && file.length() < 512 * 1024 + }.mapNotNull { file -> + try { + val relativePath = root.toPath().relativize(file.toPath()) + val text = file.readText(Charsets.UTF_8) + val tokenCount = GPT4Tokenizer().estimateTokenCount(text) + """ + * ${relativePath} - ${file.length()} bytes, ${tokenCount} tokens + """.trimIndent() + } catch (e: Exception) { + null + } + } + + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/problems/AnalyzeProblemAction.kt b/src/main/kotlin/aicoder/actions/problems/AnalyzeProblemAction.kt new file mode 100644 index 00000000..26709e9b --- /dev/null +++ b/src/main/kotlin/aicoder/actions/problems/AnalyzeProblemAction.kt @@ -0,0 +1,264 @@ +package aicoder.actions.problems + +import aicoder.actions.SessionProxyServer +import aicoder.actions.agent.toFile +import aicoder.actions.test.TestResultAutofixAction.Companion.findGitRoot +import aicoder.actions.test.TestResultAutofixAction.Companion.getProjectStructure +import aicoder.actions.test.TestResultAutofixAction.Companion.tripleTilde +import aicoder.actions.test.TestResultAutofixAction.ParsedError +import aicoder.actions.test.TestResultAutofixAction.ParsedErrors +import com.intellij.analysis.problemsView.toolWindow.ProblemNode +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiManager +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.IdeaChatClient +import com.simiacryptus.diff.AddApplyFileDiffLinks + +import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.AgentPatterns +import com.simiacryptus.skyenet.Retryable +import com.simiacryptus.skyenet.core.actors.ParsedActor +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager +import com.simiacryptus.skyenet.webui.session.SessionTask +import com.simiacryptus.skyenet.webui.session.SocketManager +import com.simiacryptus.util.JsonUtil +import java.text.SimpleDateFormat +import javax.swing.JOptionPane + +class AnalyzeProblemAction : AnAction() { + companion object { + private val log = Logger.getInstance(AnalyzeProblemAction::class.java) + } + + override fun actionPerformed(e: AnActionEvent) { + val project: Project = e.project ?: return + val item = e.getData(PlatformDataKeys.SELECTED_ITEM) as ProblemNode? ?: return + val file: VirtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return + val gitRoot = findGitRoot(file) + + Thread { + try { + val problemInfo = buildString { + appendLine("File: ${file.path}") + appendLine("Problem: ${item.text}") + + val psiFile = PsiManager.getInstance(project).findFile(file) + val fileType = if (psiFile != null) { + val fileType = psiFile.fileType.name + appendLine("File type: $fileType") + fileType + } else { + "" + } + + val document = FileDocumentManager.getInstance().getDocument(file) + if (document != null) { + val lineNumber = item.line + val column = item.column + appendLine("Position: Line ${lineNumber + 1}, Column ${column + 1}") + + // Capture 5 lines of context + val startLine = maxOf(0, lineNumber - 2) + val endLine = minOf(document.lineCount - 1, lineNumber + 2) + val contextLines = (startLine..endLine).map { line -> + val start = document.getLineStartOffset(line) + val end = document.getLineEndOffset(line) + document.getText(TextRange(start, end)) + } + appendLine("Context:") + contextLines.forEachIndexed { index, content -> + val linePrefix = if (index + startLine == lineNumber) ">" else " " + appendLine("$linePrefix ${index + startLine + 1}: $content") + } + appendLine("${" ".repeat(column + 5)}^") + } + + val projectStructure = getProjectStructure(gitRoot) + appendLine("Project structure:\n ${projectStructure.replace("\n", "\n ")}\n") + appendLine("## ${file.path}\n```${fileType.lowercase()}\n${document?.text}\n```\n") + } + log.info("Problem info: $problemInfo") + openAnalysisSession(project, problemInfo, gitRoot) + } catch (ex: Throwable) { + log.error("Error analyzing problem", ex) + JOptionPane.showMessageDialog(null, ex.message, "Error", JOptionPane.ERROR_MESSAGE) + } + }.start() + + } + + private fun openAnalysisSession(project: Project, problemInfo: String, gitRoot: VirtualFile?) { + val session = Session.newGlobalID() + SessionProxyServer.chats[session] = ProblemAnalysisApp(session, problemInfo, gitRoot) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + + val server = AppServer.getServer(project) + + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + override fun update(e: AnActionEvent) { + val project = e.project + val file = e.getData(CommonDataKeys.VIRTUAL_FILE) + e.presentation.isEnabledAndVisible = project != null && file != null + } + + inner class ProblemAnalysisApp( + val session: Session, + val problemInfo: String, + val gitRoot: VirtualFile? + ) : ApplicationServer( + applicationName = "Problem Analysis", + path = "/analyzeProblem", + showMenubar = false, + ) { + override val singleInput = true + override val stickyInput = false + + override fun newSession(user: User?, session: Session): SocketManager { + val socketManager = super.newSession(user, session) + val ui = (socketManager as ApplicationSocketManager).applicationInterface + val task = ui.newTask() + task.add("Analyzing problem and suggesting fixes...") + Thread { + analyzeProblem(ui, task, api = IdeaChatClient.instance) + }.start() + return socketManager + } + + private fun analyzeProblem(ui: ApplicationInterface, task: SessionTask, api: API) { + try { + Retryable(ui, task) { + val plan = ParsedActor( + resultClass = ParsedErrors::class.java, + prompt = """ + You are a helpful AI that helps people with coding. + Given the response of a test failure, identify one or more distinct errors. + For each error: + 1) predict the files that need to be fixed + 2) predict related files that may be needed to debug the issue + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel() + ).answer(listOf(problemInfo), api = IdeaChatClient.instance) + + task.add( + AgentPatterns.displayMapInTabs( + mapOf( + "Text" to renderMarkdown(plan.text, ui = ui), + "JSON" to renderMarkdown( + "${tripleTilde}json\n${JsonUtil.toJson(plan.obj)}\n$tripleTilde", + ui = ui + ), + ) + ) + ) + + plan.obj.errors?.forEach { error -> + Retryable(ui, task) { + val filesToFix = (error.fixFiles ?: emptyList()) + (error.relatedFiles ?: emptyList()) + val summary = filesToFix.joinToString("\n\n") { filePath -> + val file = gitRoot?.toFile?.resolve(filePath) + if (file?.exists() == true) { + """ + # $filePath + $tripleTilde${filePath.split('.').lastOrNull()} + ${file.readText()} + $tripleTilde + """.trimIndent() + } else { + "# $filePath\nFile not found" + } + } + + generateAndAddResponse(ui, task, error, summary, api) + } + } + "" + } + } catch (e: Exception) { + task.error(ui, e) + } + } + + private fun generateAndAddResponse( + ui: ApplicationInterface, + task: SessionTask, + error: ParsedError, + summary: String, + api: API + ): String { + val response = SimpleActor( + prompt = """ + You are a helpful AI that helps people with coding. + Suggest fixes for the following problem: + """.trimIndent() + problemInfo + """ + + Here are the relevant files: + """.trimIndent() + summary + """ + + Response should use one or more code patches in diff format within """.trimIndent() + tripleTilde + """diff code blocks. + Each diff should be preceded by a header that identifies the file being modified. + The diff format should use + for line additions, - for line deletions. + The diff should include 2 lines of context before and after every change. + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel() + ).answer(listOf(error.message ?: ""), api = IdeaChatClient.instance) + + return "
${ + renderMarkdown( + AddApplyFileDiffLinks.instrumentFileDiffs( + self = ui.socketManager!!, + root = root.toPath(), + response = response, + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + task.complete("$path Updated") + } + }, + ui = ui, + api = api, + ) + ) + }
" + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/aicoder/actions/test/TestResultAutofixAction.kt b/src/main/kotlin/aicoder/actions/test/TestResultAutofixAction.kt new file mode 100644 index 00000000..d4e44c03 --- /dev/null +++ b/src/main/kotlin/aicoder/actions/test/TestResultAutofixAction.kt @@ -0,0 +1,315 @@ +package aicoder.actions.test + +import aicoder.actions.BaseAction +import aicoder.actions.SessionProxyServer +import com.intellij.execution.testframework.AbstractTestProxy +import com.intellij.execution.testframework.sm.runner.SMTestProxy +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.vfs.VirtualFile +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.aicoder.util.IdeaChatClient +import com.simiacryptus.aicoder.util.UITools +import com.simiacryptus.diff.AddApplyFileDiffLinks +import com.simiacryptus.jopenai.models.chatModel +import com.simiacryptus.skyenet.AgentPatterns +import com.simiacryptus.skyenet.Retryable +import com.simiacryptus.skyenet.core.actors.ParsedActor +import com.simiacryptus.skyenet.core.actors.SimpleActor +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.core.util.FileValidationUtils.Companion.isGitignore +import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown +import com.simiacryptus.skyenet.webui.application.AppInfoData +import com.simiacryptus.skyenet.webui.application.ApplicationInterface +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager +import com.simiacryptus.skyenet.webui.session.SessionTask +import com.simiacryptus.skyenet.webui.session.SocketManager +import com.simiacryptus.util.JsonUtil +import org.jetbrains.annotations.NotNull +import org.slf4j.LoggerFactory +import java.io.File +import java.nio.file.Path +import java.text.SimpleDateFormat + +class TestResultAutofixAction : BaseAction() { + companion object { + private val log = LoggerFactory.getLogger(TestResultAutofixAction::class.java) + val tripleTilde = "`" + "``" // This is a workaround for the markdown parser when editing this file + + fun getFiles( + virtualFiles: Array? + ): MutableSet { + val codeFiles = mutableSetOf() // Set to avoid duplicates + virtualFiles?.forEach { file -> + if (file.fileName.startsWith(".")) return@forEach + if (isGitignore(file)) return@forEach + if (file.toFile().isDirectory) { + codeFiles.addAll(getFiles(file.toFile().listFiles().map { it.toPath() }.toTypedArray())) + } else { + codeFiles.add(file) + } + } + return codeFiles + } + + fun getProjectStructure(projectPath: VirtualFile?): String { + return getProjectStructure(Path.of((projectPath ?: return "Project path is null").path)) + } + + fun getProjectStructure(root: Path): String { + val codeFiles = getFiles(arrayOf(root)) + .filter { it.toFile().length() < 1024 * 1024 / 2 } // Limit to 0.5MB + .map { root.relativize(it) ?: it }.toSet() + val str = codeFiles + .asSequence() + .filter { root.resolve(it)?.toFile()?.exists() == true } + .distinct().sorted() + .joinToString("\n") { path -> + "* ${path} - ${root.resolve(path)?.toFile()?.length() ?: "?"} bytes".trim() + } + return str + } + + fun findGitRoot(path: Path?): Path? { + var current: Path? = path + while (current != null) { + if (current.resolve(".git").toFile().exists()) { + return current + } + current = current.parent + } + return null + } + + fun findGitRoot(virtualFile: VirtualFile?): VirtualFile? { + var current: VirtualFile? = virtualFile + while (current != null) { + if (current.findChild(".git") != null) { + return current + } + current = current.parent + } + return null + } + } + + override fun handle(e: AnActionEvent) { + val testProxy = e.getData(AbstractTestProxy.DATA_KEY) as? SMTestProxy ?: return + val dataContext = e.dataContext + val virtualFile = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext)?.firstOrNull() ?: return + val root = Companion.findGitRoot(virtualFile) + UITools.runAsync(e.project, "Analyzing Test Result", true) { progress -> + progress.isIndeterminate = true + progress.text = "Analyzing test failure..." + try { + val testInfo = getTestInfo(testProxy) + val projectStructure = getProjectStructure(root) + openAutofixWithTestResult(e, testInfo, projectStructure) + } catch (ex: Throwable) { + UITools.error(log, "Error analyzing test result", ex) + } + } + } + + override fun isEnabled(@NotNull e: AnActionEvent): Boolean { + val testProxy = e.getData(AbstractTestProxy.DATA_KEY) + return testProxy != null + } + + private fun getTestInfo(testProxy: SMTestProxy): String { + val sb = StringBuilder(256) // Pre-allocate buffer with reasonable size + sb.appendLine("Test Name: ${testProxy.name}") + sb.appendLine("Duration: ${testProxy.duration} ms") + + if (testProxy.errorMessage != null) { + sb.appendLine("Error Message:") + sb.appendLine(testProxy.errorMessage) + } + + if (testProxy.stacktrace != null) { + sb.appendLine("Stacktrace:") + sb.appendLine(testProxy.stacktrace) + } + + return sb.toString() + } + + private fun openAutofixWithTestResult(e: AnActionEvent, testInfo: String, projectStructure: String) { + val session = Session.newGlobalID() + SessionProxyServer.metadataStorage.setSessionName( + null, + session, + "${javaClass.simpleName} @ ${SimpleDateFormat("HH:mm:ss").format(System.currentTimeMillis())}" + ) + SessionProxyServer.chats[session] = TestResultAutofixApp(session, testInfo, e.project?.basePath, projectStructure) + ApplicationServer.appInfoMap[session] = AppInfoData( + applicationName = "Code Chat", + singleInput = false, + stickyInput = true, + loadImages = false, + showMenubar = false + ) + + val server = AppServer.getServer(e.project) + + Thread { + Thread.sleep(500) + try { + val uri = server.server.uri.resolve("/#$session") + log.info("Opening browser to $uri") + browse(uri) + } catch (e: Throwable) { + log.warn("Error opening browser", e) + } + }.start() + } + + inner class TestResultAutofixApp( + val session: Session, + val testInfo: String, + val projectPath: String?, + val projectStructure: String + ) : ApplicationServer( + applicationName = "Test Result Autofix", + path = "/fixTest", + showMenubar = false, + ) { + override val singleInput = true + override val stickyInput = false + override fun newSession(user: User?, session: Session): SocketManager { + val socketManager = super.newSession(user, session) + val ui = (socketManager as ApplicationSocketManager).applicationInterface + val task = ui.newTask() + task.add("Analyzing test result and suggesting fixes...") + Thread { + runAutofix(ui, task) + }.start() + return socketManager + } + + private fun runAutofix(ui: ApplicationInterface, task: SessionTask) { + Retryable(ui, task) { + try { + val plan = ParsedActor( + resultClass = ParsedErrors::class.java, + prompt = """ + You are a helpful AI that helps people with coding. + Given the response of a test failure, identify one or more distinct errors. + For each error: + 1) predict the files that need to be fixed + 2) predict related files that may be needed to debug the issue + + Project structure: + $projectStructure + 1) predict the files that need to be fixed + 2) predict related files that may be needed to debug the issue + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel() + ).answer(listOf(testInfo), api = IdeaChatClient.instance) + if (plan.obj.errors.isNullOrEmpty()) { + task.add("No errors identified in test result") + return@Retryable "" + } + + task.add( + AgentPatterns.displayMapInTabs( + mapOf( + "Text" to renderMarkdown(plan.text, ui = ui), + "JSON" to renderMarkdown( + "${tripleTilde}json\n${JsonUtil.toJson(plan.obj)}\n$tripleTilde", + ui = ui + ), + ) + ) + ) + + plan.obj.errors?.forEach { error -> + Retryable(ui, task) { + val filesToFix = (error.fixFiles ?: emptyList()) + (error.relatedFiles ?: emptyList()) + val summary = filesToFix.joinToString("\n\n") { filePath -> + val file = File(projectPath, filePath) + if (file.exists()) { + """ + # $filePath + $tripleTilde${filePath.split('.').lastOrNull()} + ${file.readText()} + $tripleTilde + """.trimIndent() + } else { + "# $filePath\nFile not found" + } + } + + generateAndAddResponse(ui, task, error, summary, filesToFix) + return@Retryable "" + } + } + return@Retryable "" + } catch (e: Exception) { + log.error("Error in autofix process: ${e.message}", e) + task.error(ui, e) + throw e + } + } + } + + private fun generateAndAddResponse( + ui: ApplicationInterface, + task: SessionTask, + error: ParsedError, + summary: String, + filesToFix: List + ) { + task.add("Generating fix suggestions...") + val response = SimpleActor( + prompt = """ + You are a helpful AI that helps people with coding. + Suggest fixes for the following test failure: + $testInfo + + Here are the relevant files: + $summary + +Project structure: +$projectStructure + + Response should use one or more code patches in diff format within ${tripleTilde}diff code blocks. + Each diff should be preceded by a header that identifies the file being modified. + The diff format should use + for line additions, - for line deletions. + The diff should include 2 lines of context before and after every change. + """.trimIndent(), + model = AppSettingsState.instance.smartModel.chatModel() + ).answer(listOf(error.message ?: ""), api = IdeaChatClient.instance) + task.add("Processing suggested fixes...") + + var markdown = AddApplyFileDiffLinks.instrumentFileDiffs( + ui.socketManager!!, + root = root.toPath(), + response = response, + handle = { newCodeMap -> + newCodeMap.forEach { (path, newCode) -> + task.add("Applying changes to $path...") + task.complete("$path Updated") + } + }, + ui = ui, + api = api, + ) + task.add("
${renderMarkdown(markdown!!)}
") + } + } + + data class ParsedErrors( + val errors: List? = null + ) + + data class ParsedError( + val message: String? = null, + val relatedFiles: List? = null, + val fixFiles: List? = null + ) +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/AppServer.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/AppServer.kt deleted file mode 100644 index 33bbe4e6..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/AppServer.kt +++ /dev/null @@ -1,104 +0,0 @@ -package com.github.simiacryptus.aicoder - -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.simiacryptus.skyenet.webui.chat.ChatServer -import org.eclipse.jetty.server.Server -import org.eclipse.jetty.server.handler.ContextHandlerCollection -import org.eclipse.jetty.webapp.WebAppContext -import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer -import org.slf4j.LoggerFactory -import java.net.InetSocketAddress - -class AppServer( - private val localName: String, - private val port: Int, - project: Project? -) { - - private val log by lazy { LoggerFactory.getLogger(javaClass) } - - val server by lazy { - val server = Server(InetSocketAddress(localName, port)) - server.handler = contexts - server - } - - private val handlers = arrayOf( - newWebAppContext(SessionProxyServer(), "/") - ).toMutableList() - - private val contexts by lazy { - val contexts = ContextHandlerCollection() - contexts.handlers = handlers.toTypedArray() - contexts - } - - private fun newWebAppContext(server: ChatServer, path: String): WebAppContext { - val context = WebAppContext() - JettyWebSocketServletContainerInitializer.configure(context, null) - context.baseResource = server.baseResource - context.classLoader = AppServer::class.java.classLoader - context.contextPath = path - context.welcomeFiles = arrayOf("index.html") - server.configure(context) - return context - } - - - private val serverLock = Object() -// private val progressThread = Thread { -// try { -// UITools.run( -// project, "Running CodeChat Server on $port", false -// ) { -// while (isRunning(it)) { -// Thread.sleep(1000) -// } -// synchronized(serverLock) { -// if (it.isCanceled) { -// log.info("Server cancelled") -// server.stop() -// } else { -// log.info("Server stopped") -// } -// } -// } -// } finally { -// log.info("Stopping Server") -// server.stop() -// } -// } - - private fun isRunning(it: ProgressIndicator) = synchronized(serverLock) { !it.isCanceled && server.isRunning } - - fun start() { - server.start() -// progressThread.start() - } - - companion object { - @Transient - private var server: AppServer? = null - fun isRunning(): Boolean { - return server?.server?.isRunning ?: false - } - - fun getServer(project: Project?): AppServer { - if (null == server || !server!!.server.isRunning) { - server = AppServer( - AppSettingsState.instance.listeningEndpoint, - AppSettingsState.instance.listeningPort, - project - ) - server!!.start() - } - return server!! - } - - } - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/ApplyPatchAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/ApplyPatchAction.kt deleted file mode 100644 index d73367b0..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/ApplyPatchAction.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.github.simiacryptus.aicoder.actions - -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.command.WriteCommandAction -import com.intellij.openapi.ui.Messages -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.PsiManager -import com.simiacryptus.diff.IterativePatchUtil - -class ApplyPatchAction : BaseAction( - name = "Apply Patch", - description = "Applies a patch to the current file" -) { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(event: AnActionEvent) { - val project = event.project ?: return - val virtualFiles = UITools.getSelectedFiles(event) ?: return - - // Prompt user to input patch content - val patchContent = Messages.showMultilineInputDialog( - project, - "Enter the patch content:", - "Input Patch", - "", - null, - null - ) ?: return - virtualFiles.forEach { virtualFile -> - applyPatch(virtualFile, patchContent, project) - } - } - - private fun applyPatch(file: VirtualFile, patchContent: String, project: com.intellij.openapi.project.Project) { - WriteCommandAction.runWriteCommandAction(project) { - val psiFile = PsiManager.getInstance(project).findFile(file) ?: return@runWriteCommandAction - val newContent = IterativePatchUtil.applyPatch(psiFile.text, patchContent) - psiFile.virtualFile.setBinaryContent(newContent.toByteArray()) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/BaseAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/BaseAction.kt deleted file mode 100644 index 0efc61ce..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/BaseAction.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.github.simiacryptus.aicoder.actions - -import com.github.simiacryptus.aicoder.util.IdeaChatClient -import com.github.simiacryptus.aicoder.util.IdeaOpenAIClient -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.simiacryptus.jopenai.ChatClient -import org.slf4j.LoggerFactory -import javax.swing.Icon - -abstract class BaseAction( - name: String? = null, - description: String? = null, - icon: Icon? = null, -) : AnAction(name, description, icon) { - - private val log by lazy { LoggerFactory.getLogger(javaClass) } - //override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT - - val api: ChatClient - get() = IdeaChatClient.instance - val api2 = IdeaOpenAIClient.instance - - final override fun update(event: AnActionEvent) { - event.presentation.isEnabledAndVisible = isEnabled(event) - super.update(event) - } - - abstract fun handle(e: AnActionEvent) - - - final override fun actionPerformed(e: AnActionEvent) { - UITools.logAction( - """ - |Action: ${javaClass.simpleName} - """.trimMargin().trim() - ) - IdeaChatClient.lastEvent = e - try { - handle(e) - } catch (e: Throwable) { - UITools.error(log, "Error in Action ${javaClass.simpleName}", e) - } - } - - open fun isEnabled(event: AnActionEvent): Boolean = true - - - companion object { - val log by lazy { LoggerFactory.getLogger(javaClass) } - val scheduledPool = java.util.concurrent.Executors.newScheduledThreadPool(1) - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/FileContextAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/FileContextAction.kt deleted file mode 100644 index aa19a35d..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/FileContextAction.kt +++ /dev/null @@ -1,124 +0,0 @@ -package com.github.simiacryptus.aicoder.actions - -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.LocalFileSystem -import com.intellij.openapi.vfs.VirtualFile -import org.slf4j.LoggerFactory -import java.io.File -import java.nio.file.Path -import java.util.concurrent.TimeUnit - -abstract class FileContextAction( - private val supportsFiles: Boolean = true, - private val supportsFolders: Boolean = true, -) : BaseAction() { - - data class SelectionState( - val selectedFile: File, - val projectRoot: File, - ) - - abstract fun processSelection(state: SelectionState, config: T?, progress: ProgressIndicator): Array - - final override fun handle(e: AnActionEvent) { - val config = getConfig(e.project, e) - if (config == null) { - log.warn("No configuration found for ${javaClass.simpleName}") - return - } - val virtualFile = UITools.getSelectedFile(e) ?: UITools.getSelectedFolder(e) ?: return - val project = e.project ?: return - val projectRoot = File(project.basePath!!).toPath() - Thread { - try { - UITools.redoableTask(e) { - UITools.run(e.project, templateText!!, true) { progress -> - val newFiles = try { - processSelection( - SelectionState( - selectedFile = virtualFile.toNioPath().toFile(), - projectRoot = projectRoot.toFile(), - ), config, progress - ) - } finally { - if (progress.isCanceled) throw InterruptedException() - } - val start = System.currentTimeMillis() - val fileSystem = LocalFileSystem.getInstance() - while (null == fileSystem.refreshAndFindFileByIoFile(newFiles.firstOrNull() ?: throw IllegalStateException())) { - if (System.currentTimeMillis() - start > 10000) { - throw IllegalStateException("File not found: ${newFiles.firstOrNull()}") - } - Thread.sleep(500) - } - UITools.writeableFn(e) { - val files = newFiles.mapNotNull { file -> - val generatedFile = fileSystem.refreshAndFindFileByIoFile(file) - if (generatedFile == null) { - log.warn("Generated file not found: ${file.path}") - } else { - open(project, file.toPath()) - } - generatedFile - }.toTypedArray() - Runnable { - files.forEach { it?.delete(this@FileContextAction) } - } - } - } - } - } catch (e: Throwable) { - UITools.error(log, "Error in ${javaClass.simpleName}", e) - } - }.start() - } - - open fun getConfig(project: Project?, e: AnActionEvent): T? = null - - var isDevAction = false - override fun isEnabled(event: AnActionEvent): Boolean { - if (!super.isEnabled(event)) return false - if (isDevAction && !AppSettingsState.instance.devActions) return false - val virtualFile = UITools.getSelectedFile(event) ?: UITools.getSelectedFolder(event) ?: return false - return if (virtualFile.isDirectory) supportsFolders else supportsFiles - } - - companion object { - private val log = LoggerFactory.getLogger(FileContextAction::class.java) - - fun open(project: Project, outputPath: Path) { - log.info("Opening file: $outputPath") - lateinit var function: () -> Unit - function = { - val file = outputPath.toFile() - if (file.exists()) { - // Ensure the IDE is ready for file operations - ApplicationManager.getApplication().invokeLater { - val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) - if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { - val localFileSystem = LocalFileSystem.getInstance() - // Refresh the file system to ensure the file is visible - val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) - virtualFile?.let { - FileEditorManager.getInstance(project).openFile(it, true) - } ?: scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } else { - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - } else { - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - - } - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/OpenWebPageAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/OpenWebPageAction.kt deleted file mode 100644 index 65951ac3..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/OpenWebPageAction.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.github.simiacryptus.aicoder.actions - -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import java.net.URI - -class OpenWebPageAction : AnAction() { - override fun actionPerformed(event: AnActionEvent) { - browse(URI("http://apps.simiacrypt.us/")) - } - -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/SelectionAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/SelectionAction.kt deleted file mode 100644 index 514d154c..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/SelectionAction.kt +++ /dev/null @@ -1,202 +0,0 @@ -package com.github.simiacryptus.aicoder.actions - -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.LanguageUtils -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.command.WriteCommandAction -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.editor.RangeMarker -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.intellij.openapi.project.Project -import com.intellij.openapi.util.NlsSafe -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiManager -import com.intellij.psi.PsiRecursiveElementVisitor - -abstract class SelectionAction( - private val requiresSelection: Boolean = true -) : BaseAction() { - - open fun getConfig(project: Project?): T? = null - - private fun retarget( - editorState: EditorState, - selectedText: @NlsSafe String?, - selectionStart: Int, - selectionEnd: Int - ): Pair? { - if (selectedText.isNullOrEmpty()) { - var (start, end) = defaultSelection(editorState, selectionStart) - if (start >= end && requiresSelection) return null - start = start.coerceAtLeast(0) - end = end.coerceAtLeast(start).coerceAtMost(editorState.text.length - 1) - return Pair(start, end) - } else { - var (start, end) = editSelection(editorState, selectionStart, selectionEnd) - if (start >= end && requiresSelection) return null - start = start.coerceAtLeast(0) - end = end.coerceAtLeast(start).coerceAtMost(editorState.text.length - 1) - return Pair(start, end) - } - } - - final override fun handle(e: AnActionEvent) { - val editor = e.getData(CommonDataKeys.EDITOR) ?: return - val config = getConfig(e.project) - val indent = UITools.getIndent(e) - val caretModel = editor.caretModel - val primaryCaret = caretModel.primaryCaret - var selectionStart = primaryCaret.selectionStart - var selectionEnd = primaryCaret.selectionEnd - var selectedText = primaryCaret.selectedText - val editorState = editorState(editor) - val (start, end) = retarget(editorState, selectedText, selectionStart, selectionEnd) ?: return - val text = editorState.text - selectedText = text.substring(start.coerceIn(0, (text.length - 1).coerceAtLeast(0)), end.coerceIn(0, (text.length - 1).coerceAtLeast(0))) - selectionEnd = end.coerceIn(0, (text.length - 1).coerceAtLeast(0)) - selectionStart = start.coerceIn(0, (text.length - 1).coerceAtLeast(0)) - - UITools.redoableTask(e) { - val document = e.getData(CommonDataKeys.EDITOR)?.document - var rangeMarker: RangeMarker? = null - WriteCommandAction.runWriteCommandAction(e.project) { - rangeMarker = document?.createGuardedBlock(selectionStart, selectionEnd) - } - - val newText = try { - processSelection( - event = e, - SelectionState( - selectedText = selectedText, - selectionOffset = selectionStart, - selectionLength = selectionEnd - selectionStart, - entireDocument = editor.document.text, - language = LanguageUtils.getComputerLanguage(e), - indent = indent, - contextRanges = editorState.contextRanges, - psiFile = editorState.psiFile, - project = e.project - ), - config = config - ) - } finally { - if (null != rangeMarker) - WriteCommandAction.runWriteCommandAction(e.project) { - document?.removeGuardedBlock(rangeMarker!!) - } - } - UITools.writeableFn(e) { - UITools.replaceString(editor.document, selectionStart, selectionEnd, newText) - } - } - } - - data class EditorState( - val text: @NlsSafe String, - val cursorOffset: Int, - val line: Pair, - val psiFile: PsiFile?, - val contextRanges: Array = arrayOf(), - ) - - data class ContextRange( - val name: String, - val start: Int, - val end: Int - ) { - fun length() = end - start - fun range() = Pair(start, end) - - fun subString(text: String) = text.substring(start, end) - } - - private fun editorState(editor: Editor): EditorState { - val document = editor.document - val lineNumber = document.getLineNumber(editor.caretModel.offset) - val virtualFile = FileDocumentManager.getInstance().getFile(editor.document) - val psiFile = if (virtualFile == null) { - null - } else { - PsiManager.getInstance(editor.project!!).findFile(virtualFile) - } - return EditorState( - text = document.text, - cursorOffset = editor.caretModel.offset, - line = Pair(document.getLineStartOffset(lineNumber), document.getLineEndOffset(lineNumber)), - psiFile = psiFile, - contextRanges = contextRanges(psiFile, editor) - ) - } - - private fun contextRanges( - psiFile: PsiFile?, - editor: Editor - ): Array { - val contextRanges = mutableListOf() - psiFile?.acceptChildren(object : PsiRecursiveElementVisitor() { - override fun visitElement(element: PsiElement) { - val start = element.textRange.startOffset - val end = element.textRange.endOffset - if (start <= editor.caretModel.offset && end >= editor.caretModel.offset) { - contextRanges.add(ContextRange(element.javaClass.simpleName, start, end)) - } - super.visitElement(element) - } - }) - return contextRanges.toTypedArray() - } - - - override fun isEnabled(event: AnActionEvent): Boolean { - if (!super.isEnabled(event)) return false - val editor = event.getData(CommonDataKeys.EDITOR) ?: return false - if (requiresSelection) { - if (editor.caretModel.primaryCaret.selectedText.isNullOrEmpty()) { - val editorState = editorState(editor) - val (start, end) = defaultSelection(editorState, editorState.cursorOffset) - if (start >= end) return false - } - } - val computerLanguage = LanguageUtils.getComputerLanguage(event) - return isLanguageSupported(computerLanguage) - } - - data class SelectionState( - val selectedText: String? = null, - val selectionOffset: Int = 0, - val selectionLength: Int? = null, - val entireDocument: String? = null, - val language: ComputerLanguage? = null, - val indent: CharSequence? = null, - val contextRanges: Array = arrayOf(), - val psiFile: PsiFile?, - val project: Project? - ) - - open fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - return LanguageUtils.isLanguageSupported(computerLanguage) - } - - open fun defaultSelection(editorState: EditorState, offset: Int) = editorState.line - - open fun editSelection(state: EditorState, start: Int, end: Int) = Pair(start, end) - - - open fun processSelection( - event: AnActionEvent?, - selectionState: SelectionState, - config: T? - ): String { - return UITools.run(event?.project, templateText ?: "", true) { - processSelection(selectionState, config) - } - } - - open fun processSelection(state: SelectionState, config: T?): String { - throw NotImplementedError() - } - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CustomEditAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CustomEditAction.kt deleted file mode 100644 index 156bd5d1..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/CustomEditAction.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy -import javax.swing.JOptionPane - -open class CustomEditAction : SelectionAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - interface VirtualAPI { - fun editCode( - code: String, - operation: String, - computerLanguage: String, - humanLanguage: String - ): EditedText - - data class EditedText( - var code: String? = null, - var language: String? = null - ) - } - - val proxy: VirtualAPI - get() { - val chatProxy = ChatProxy( - clazz = VirtualAPI::class.java, - api = api, - temperature = AppSettingsState.instance.temperature, - model = AppSettingsState.instance.smartModel.chatModel(), - ) - chatProxy.addExample( - VirtualAPI.EditedText( - """ - // Print Hello, World! to the console - println("Hello, World!") - """.trimIndent(), - "java" - ) - ) { - it.editCode( - """println("Hello, World!")""", - "Add code comments", - "java", - "English" - ) - } - return chatProxy.create() - } - - override fun getConfig(project: Project?): String { - return UITools.showInputDialog( - null, "Instruction:", "Edit Code", JOptionPane.QUESTION_MESSAGE - //, AppSettingsState.instance.getRecentCommands("customEdits").mostRecentHistory - ) as String? ?: "" - } - - override fun processSelection(state: SelectionState, instruction: String?): String { - if (instruction == null || instruction.isBlank()) return state.selectedText ?: "" - val settings = AppSettingsState.instance - val outputHumanLanguage = AppSettingsState.instance.humanLanguage - settings.getRecentCommands("customEdits").addInstructionToHistory(instruction) - return proxy.editCode( - state.selectedText ?: "", - instruction, - state.language?.name ?: "", - outputHumanLanguage - ).code ?: state.selectedText ?: "" - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DescribeAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DescribeAction.kt deleted file mode 100644 index cf31c9c4..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/DescribeAction.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.IndentedText -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy -import com.simiacryptus.util.StringUtil - -class DescribeAction : SelectionAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - interface DescribeAction_VirtualAPI { - fun describeCode( - code: String, - computerLanguage: String, - humanLanguage: String - ): DescribeAction_ConvertedText - - class DescribeAction_ConvertedText { - var text: String? = null - var language: String? = null - } - } - - private val proxy: DescribeAction_VirtualAPI - get() = ChatProxy( - clazz = DescribeAction_VirtualAPI::class.java, - api = api, - temperature = AppSettingsState.instance.temperature, - model = AppSettingsState.instance.smartModel.chatModel(), - deserializerRetries = 5 - ).create() - - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(state: SelectionState, config: String?): String { - val description = proxy.describeCode( - IndentedText.fromString(state.selectedText).textBlock.toString().trim(), - state.language?.name ?: "", - AppSettingsState.instance.humanLanguage - ).text ?: "" - val wrapping = StringUtil.lineWrapping(description.trim(), 120) - val numberOfLines = wrapping.trim().split("\n").reversed().dropWhile { it.isEmpty() }.size - val commentStyle = if (numberOfLines == 1) { - state.language?.lineComment - } else { - state.language?.blockComment - } - return buildString { - append(state.indent) - append(commentStyle?.fromString(wrapping)?.withIndent(state.indent!!) ?: wrapping) - append("\n") - append(state.indent) - append(state.selectedText) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/PasteAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/PasteAction.kt deleted file mode 100644 index ed745ff6..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/PasteAction.kt +++ /dev/null @@ -1,144 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.ChatModel -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy -import org.jsoup.Jsoup -import org.jsoup.nodes.Document -import java.awt.Toolkit -import java.awt.datatransfer.DataFlavor -import kotlin.toString - -abstract class PasteActionBase(private val model: (AppSettingsState) -> ChatModel) : SelectionAction(false) { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - interface VirtualAPI { - fun convert(text: String, from_language: String, to_language: String): ConvertedText - - class ConvertedText { - var code: String? = null - var language: String? = null - } - } - - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(state: SelectionState, config: String?): String { - val text = getClipboard().toString().trim() - return ChatProxy( - VirtualAPI::class.java, - api, - model(AppSettingsState.instance), - AppSettingsState.instance.temperature, - ).create().convert( - text, - "autodetect", - state.language?.name ?: "" - ).code ?: "" - } - - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - if (computerLanguage == null) return false - return computerLanguage != ComputerLanguage.Text - } - - override fun isEnabled(event: AnActionEvent): Boolean { - if (!hasClipboard()) return false - return super.isEnabled(event) - } - - private fun hasClipboard() = Toolkit.getDefaultToolkit().systemClipboard.getContents(null)?.let { contents -> - return when { - contents.isDataFlavorSupported(DataFlavor.stringFlavor) -> true - contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()) -> true - else -> false - } - } ?: false - - private fun getClipboard(): Any? { - val toolkit = Toolkit.getDefaultToolkit() - val systemClipboard = toolkit.systemClipboard - return systemClipboard.getContents(null)?.let { contents -> - return when { - contents.isDataFlavorSupported(DataFlavor.selectionHtmlFlavor) -> contents.getTransferData(DataFlavor.selectionHtmlFlavor).let { scrubHtml(it.toString().trim()) } - contents.isDataFlavorSupported(DataFlavor.fragmentHtmlFlavor) -> contents.getTransferData(DataFlavor.fragmentHtmlFlavor).let { scrubHtml(it.toString().trim()) } - contents.isDataFlavorSupported(DataFlavor.allHtmlFlavor) -> contents.getTransferData(DataFlavor.allHtmlFlavor).let { scrubHtml(it.toString().trim()) } - contents.isDataFlavorSupported(DataFlavor.stringFlavor) -> contents.getTransferData(DataFlavor.stringFlavor) - contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()) -> contents.getTransferData( - DataFlavor.getTextPlainUnicodeFlavor() - ) - - else -> null - } - } - } - - protected open fun scrubHtml(str: String, maxLength: Int = 100 * 1024): String { - val document: Document = Jsoup.parse(str) - // Remove unnecessary elements, attributes, and optimize the document - document.apply { - if (document.body().html().length > maxLength) return@apply - select("script, style, link, meta, iframe, noscript").remove() // Remove unnecessary and potentially harmful tags - outputSettings().prettyPrint(false) // Disable pretty printing for compact output - if (document.body().html().length > maxLength) return@apply - // Remove comments - select("*").forEach { it.childNodes().removeAll { node -> node.nodeName() == "#comment" } } - if (document.body().html().length > maxLength) return@apply - // Remove data-* attributes - select("*[data-*]").forEach { it.attributes().removeAll { attr -> attr.key.startsWith("data-") } } - if (document.body().html().length > maxLength) return@apply - select("*").forEach { element -> - val importantAttributes = setOf("href", "src", "alt", "title", "width", "height", "style", "class", "id", "name") - element.attributes().removeAll { it.key !in importantAttributes } - } - if (document.body().html().length > maxLength) return@apply - // Remove empty elements - select("*").filter { it.text().isBlank() && it.attributes().isEmpty() && !it.hasAttr("img") }.forEach { remove() } - if (document.body().html().length > maxLength) return@apply - // Unwrap single-child elements with no attributes - select("*").forEach { element -> - if (element.childNodes().size == 1 && element.childNodes()[0].nodeName() == "#text" && element.attributes().isEmpty()) { - element.unwrap() - } - } - if (document.body().html().length > maxLength) return@apply - // Convert relative URLs to absolute - select("[href],[src]").forEach { element -> - element.attr("href")?.let { href -> element.attr("href", href.makeAbsolute()) } - element.attr("src")?.let { src -> element.attr("src", src.makeAbsolute()) } - } - if (document.body().html().length > maxLength) return@apply - // Remove empty attributes - select("*").forEach { element -> - element.attributes().removeAll { it.value.isBlank() } - } - } - - // Truncate if necessary - val result = document.body().html() - return if (result.length > maxLength) { - result.substring(0, maxLength) - } else { - result - } - } - - private fun String.makeAbsolute(): String { - return if (startsWith("http://") || startsWith("https://") || startsWith("//")) { - this - } else { - "https://$this" - } - } -} - -class SmartPasteAction : PasteActionBase({ it.smartModel.chatModel() }) -class FastPasteAction : PasteActionBase({ it.fastModel.chatModel() }) \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RecentCodeEditsAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RecentCodeEditsAction.kt deleted file mode 100644 index 03236bb9..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RecentCodeEditsAction.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.code - -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionGroup -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project - -class RecentCodeEditsAction : ActionGroup() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun update(e: AnActionEvent) { - e.presentation.isEnabledAndVisible = isEnabled(e) - super.update(e) - } - - override fun getChildren(e: AnActionEvent?): Array { - if (e == null) return emptyArray() - val children = mutableListOf() - for (instruction in AppSettingsState.instance.getRecentCommands("customEdits").getMostRecent(10)) { - val id = children.size + 1 - val text = if (id < 10) "_$id: $instruction" else "$id: $instruction" - val element = object : CustomEditAction() { - override fun getConfig(project: Project?): String { - return instruction - } - } - element.templatePresentation.text = text - element.templatePresentation.description = instruction - element.templatePresentation.icon = null - children.add(element) - } - return children.toTypedArray() - } - - companion object { - fun isEnabled(e: AnActionEvent): Boolean { - if (!UITools.hasSelection(e)) return false - val computerLanguage = ComputerLanguage.getComputerLanguage(e) - return computerLanguage != ComputerLanguage.Text - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RedoLast.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RedoLast.kt deleted file mode 100644 index 23dac9ef..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/code/RedoLast.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.code - -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.util.UITools.retry -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys - -/** - * The RedoLast action is an IntelliJ action that allows users to redo the last AI Coder action they performed in the editor. - * To use this action, open the editor and select the RedoLast action from the editor context menu. - * This will redo the last action that was performed in the editor. - */ -class RedoLast : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(e: AnActionEvent) { - retry[e.getRequiredData(CommonDataKeys.EDITOR).document]!!.run() - } - - override fun isEnabled(event: AnActionEvent): Boolean { - return null != retry[event.getRequiredData(CommonDataKeys.EDITOR).document] - } - -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/LineFilterChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/LineFilterChatAction.kt deleted file mode 100644 index 6810c357..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/LineFilterChatAction.kt +++ /dev/null @@ -1,110 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.dev - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.chat.ChatSocketManager -import com.simiacryptus.skyenet.webui.session.SessionTask -import org.slf4j.LoggerFactory - -class LineFilterChatAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - val path = "/codeChat" - - override fun handle(e: AnActionEvent) { - val editor = e.getData(CommonDataKeys.EDITOR) ?: return - val session = Session.newGlobalID() - val language = ComputerLanguage.getComputerLanguage(e)?.name ?: return - val filename = FileDocumentManager.getInstance().getFile(editor.document)?.name ?: return - val code = editor.caretModel.primaryCaret.selectedText ?: editor.document.text - val lines = code.split("\n").toTypedArray() - val codelines = lines.withIndex().joinToString("\n") { (i, line) -> - "${i.toString().padStart(3, '0')} $line" - } - SessionProxyServer.agents[session] = object : ChatSocketManager( - session = session, - model = AppSettingsState.instance.smartModel.chatModel(), - userInterfacePrompt = """ - |# `$filename` - | - |```$language - |${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} - |``` - """.trimMargin().trim(), - systemPrompt = """ - |You are a helpful AI that helps people with coding. - | - |You will be answering questions about the following code located in `$filename`: - | - |```$language - |${codelines.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} - |``` - | - |Responses may use markdown formatting. Lines from the prompt can be included by using the line number in a response line (e.g. `\nLINE\n`). - | - |For example: - | - |```text - |001 - |## Injected subtitle - | - |025 - |026 - | - |013 - |014 - |``` - """.trimMargin(), - api = api, - applicationClass = ApplicationServer::class.java, - storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome), - ) { - override fun canWrite(user: User?): Boolean = true - override fun renderResponse(response: String, task: SessionTask): String { - return renderMarkdown(response.split("\n").joinToString("\n") { - when { - // Is numeric, use line if in range - it.toIntOrNull()?.let { i -> lines.indices.contains(i) } == true -> lines[it.toInt()] - // Otherwise, use response - else -> it - } - } - ) - } - } - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.devActions - - companion object { - private val log = LoggerFactory.getLogger(LineFilterChatAction::class.java) - - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/PrintTreeAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/PrintTreeAction.kt deleted file mode 100644 index 70497435..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/dev/PrintTreeAction.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.dev - -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.psi.PsiUtil -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import org.slf4j.LoggerFactory - -/** - * The PrintTreeAction class is an IntelliJ action that enables developers to print the tree structure of a PsiFile. - * To use this action, first make sure that the "devActions" setting is enabled. - * Then, open the file you want to print the tree structure of. - * Finally, select the "PrintTreeAction" action from the editor context menu. - * This will print the tree structure of the file to the log. - */ -class PrintTreeAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(e: AnActionEvent) { - log.warn(PsiUtil.printTree(PsiUtil.getLargestContainedEntity(e)!!)) - } - - override fun isEnabled(event: AnActionEvent): Boolean { - return AppSettingsState.instance.devActions - } - - companion object { - private val log = LoggerFactory.getLogger(PrintTreeAction::class.java) - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CodeChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CodeChatAction.kt deleted file mode 100644 index d1acd045..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CodeChatAction.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.CodeChatSocketManager -import com.github.simiacryptus.aicoder.util.LanguageUtils -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import org.slf4j.LoggerFactory - -class CodeChatAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(e: AnActionEvent) { - val editor = e.getData(CommonDataKeys.EDITOR) ?: return - - val session = Session.newGlobalID() - val language = LanguageUtils.getComputerLanguage(e)?.name ?: "" - val filename = FileDocumentManager.getInstance().getFile(editor.document)?.name ?: return - - SessionProxyServer.agents[session] = CodeChatSocketManager( - session = session, - language = language, - codeSelection = editor.caretModel.primaryCaret.selectedText ?: editor.document.text, - filename = filename, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) - ) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - override fun isEnabled(event: AnActionEvent) = true - - companion object { - private val log = LoggerFactory.getLogger(CodeChatAction::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CommandAutofixAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CommandAutofixAction.kt deleted file mode 100644 index 022bf0d2..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CommandAutofixAction.kt +++ /dev/null @@ -1,199 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.ComboBox -import com.intellij.openapi.ui.DialogWrapper -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.apps.general.CmdPatchApp -import com.simiacryptus.skyenet.apps.general.PatchApp -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import org.slf4j.LoggerFactory -import java.awt.BorderLayout -import java.io.File -import java.nio.file.Files -import javax.swing.* -import kotlin.collections.set - -class CommandAutofixAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(event: AnActionEvent) { - val settings = getUserSettings(event) ?: return - val dataContext = event.dataContext - val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) - val folder = UITools.getSelectedFolder(event) - val root = if (null != folder) { - folder.toFile.toPath() - } else { - event.project?.basePath?.let { File(it).toPath() } - }!! - val session = Session.newGlobalID() - val patchApp = CmdPatchApp( - root, - session, - settings, - api, - virtualFiles?.map { it.toFile }?.toTypedArray(), - AppSettingsState.instance.smartModel.chatModel() - ) - SessionProxyServer.chats[session] = patchApp - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - val server = AppServer.getServer(event.project) - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - override fun isEnabled(event: AnActionEvent) = true - - companion object { - private val log = LoggerFactory.getLogger(CommandAutofixAction::class.java) - - private fun getUserSettings(event: AnActionEvent?): PatchApp.Settings? { - val root = UITools.getSelectedFolder(event ?: return null)?.toNioPath() ?: event.project?.basePath?.let { - File(it).toPath() - } - val files = UITools.getSelectedFiles(event).map { it.path.let { File(it).toPath() } }.toMutableSet() - if (files.isEmpty()) Files.walk(root) - .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } - .toList().filterNotNull().forEach { files.add(it) } - val settingsUI = SettingsUI(root!!.toFile()) - val dialog = CommandSettingsDialog(event.project, settingsUI) - dialog.show() - return if (dialog.isOK) { - val executable = File(settingsUI.commandField.selectedItem?.toString() ?: return null) - AppSettingsState.instance.executables += executable.absolutePath - val argument = settingsUI.argumentsField.selectedItem?.toString() ?: "" - AppSettingsState.instance.recentArguments.remove(argument) - AppSettingsState.instance.recentArguments.add(0, argument) - AppSettingsState.instance.recentArguments = - AppSettingsState.instance.recentArguments.take(10).toMutableList() - PatchApp.Settings( - executable = executable, - arguments = argument, - workingDirectory = File(settingsUI.workingDirectoryField.text), - exitCodeOption = if (settingsUI.exitCodeZero.isSelected) "0" else if (settingsUI.exitCodeAny.isSelected) "any" else "nonzero", - additionalInstructions = settingsUI.additionalInstructionsField.text, - autoFix = settingsUI.autoFixCheckBox.isSelected - ) - } else { - null - } - } - - class SettingsUI(root: File) { - val argumentsField = ComboBox().apply { - isEditable = true - AppSettingsState.instance.recentArguments.forEach { addItem(it) } - if (AppSettingsState.instance.recentArguments.isEmpty()) { - addItem("run build") - } - } - val commandField = ComboBox(AppSettingsState.instance.executables.toTypedArray()).apply { - isEditable = true - } - val commandButton = JButton("...").apply { - addActionListener { - val fileChooser = JFileChooser().apply { - fileSelectionMode = JFileChooser.FILES_ONLY - isMultiSelectionEnabled = false - } - if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { - commandField.selectedItem = fileChooser.selectedFile.absolutePath - } - } - } - val workingDirectoryField = JTextField(root.absolutePath).apply { - isEditable = true - } - val workingDirectoryButton = JButton("...").apply { - addActionListener { - val fileChooser = JFileChooser().apply { - fileSelectionMode = JFileChooser.DIRECTORIES_ONLY - isMultiSelectionEnabled = false - this.selectedFile = File(workingDirectoryField.text) - } - if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { - workingDirectoryField.text = fileChooser.selectedFile.absolutePath - } - } - } - val exitCodeOptions = ButtonGroup() - val exitCodeNonZero = JRadioButton("Patch nonzero exit code", true) - val exitCodeZero = JRadioButton("Patch 0 exit code") - val exitCodeAny = JRadioButton("Patch any exit code") - val additionalInstructionsField = JTextArea().apply { - rows = 3 - lineWrap = true - wrapStyleWord = true - } - val autoFixCheckBox = JCheckBox("Auto-apply fixes").apply { - isSelected = false - } - } - - class CommandSettingsDialog(project: Project?, private val settingsUI: SettingsUI) : DialogWrapper(project) { - init { - settingsUI.exitCodeOptions.add(settingsUI.exitCodeNonZero) - settingsUI.exitCodeOptions.add(settingsUI.exitCodeZero) - settingsUI.exitCodeOptions.add(settingsUI.exitCodeAny) - title = "Command Autofix Settings" - init() - } - - override fun createCenterPanel(): JComponent { - val panel = JPanel(BorderLayout()).apply { - - val optionsPanel = JPanel().apply { - layout = BoxLayout(this, BoxLayout.Y_AXIS) - add(JLabel("Executable")) - add(JPanel(BorderLayout()).apply { - add(settingsUI.commandField, BorderLayout.CENTER) - add(settingsUI.commandButton, BorderLayout.EAST) - }) - add(JLabel("Arguments")) - add(settingsUI.argumentsField) - add(JLabel("Working Directory")) - add(JPanel(BorderLayout()).apply { - add(settingsUI.workingDirectoryField, BorderLayout.CENTER) - add(settingsUI.workingDirectoryButton, BorderLayout.EAST) - }) - add(JLabel("Exit Code Options")) - add(settingsUI.exitCodeNonZero) - add(settingsUI.exitCodeAny) - add(settingsUI.exitCodeZero) - add(JLabel("Additional Instructions")) - add(JScrollPane(settingsUI.additionalInstructionsField)) - add(settingsUI.autoFixCheckBox) - } - add(optionsPanel, BorderLayout.SOUTH) - } - return panel - } - } - - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileFromDescriptionAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileFromDescriptionAction.kt deleted file mode 100644 index e09e93a8..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateFileFromDescriptionAction.kt +++ /dev/null @@ -1,126 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.actions.FileContextAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.Name -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.ApiModel.* -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import java.io.File -import javax.swing.JTextArea - -class CreateFileFromDescriptionAction : FileContextAction(false, true) { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - class ProjectFile(var path: String = "", var code: String = "") - - class SettingsUI { - @Name("Directive") - var directive: JTextArea = JTextArea( - """ - Create a new file - """.trimIndent(), - 3, - 120 - ) - } - - class Settings( - var directive: String = "", - val project: Project? = null - ) - - override fun getConfig(project: Project?, e: AnActionEvent): Settings { - val userSettings = UITools.showDialog( - project, - SettingsUI::class.java, - Settings::class.java, - "Create File From Description" - ) - return Settings(userSettings?.directive ?: "", project) - } - - override fun processSelection( - state: SelectionState, - config: Settings?, - progress: ProgressIndicator - ): Array { - val projectRoot = state.projectRoot.toPath() - val inputPath = projectRoot.relativize(state.selectedFile.toPath()).toString() - val pathSegments = inputPath.split("/").toList() - val updirSegments = pathSegments.takeWhile { it == ".." } - val moduleRoot = projectRoot.resolve(pathSegments.take(updirSegments.size * 2).joinToString("/")) - val filePath = pathSegments.drop(updirSegments.size * 2).joinToString("/") - - val generatedFile = generateFile(filePath, config?.directive ?: "Create a new file") - - var path = generatedFile.path - var outputPath = moduleRoot.resolve(path) - if (outputPath.toFile().exists()) { - val extension = path.substringAfterLast(".") - val name = path.substringBeforeLast(".") - val fileIndex = (1..Int.MAX_VALUE).find { - !File("$name.$it.$extension").exists() - } - path = "$name.$fileIndex.$extension" - outputPath = moduleRoot.resolve(path) - } else { - outputPath = moduleRoot.resolve(path) - } - outputPath.parent.toFile().mkdirs() - outputPath.toFile().writeText(generatedFile.code) - Thread.sleep(100) - - return arrayOf(outputPath.toFile()) - } - - private fun generateFile( - basePath: String, - directive: String - ): ProjectFile { - val model = AppSettingsState.instance.smartModel.chatModel() - val chatRequest = ChatRequest( - model = model.modelName, - temperature = AppSettingsState.instance.temperature, - messages = listOf( - ChatMessage( - Role.system, """ - You will interpret natural language requirements to create a new file. - Provide a new filename and the code to be written to the file. - Paths should be relative to the project root and should not exist. - Output the file path using the a line with the format "File: ". - Output the file code directly after the header line with no additional decoration. - """.trimIndent().toContentList(), null - ), - ChatMessage( - Role.user, """ - Create a new file based on the following directive: $directive - - The file location should be based on the selected path `$basePath` - """.trimIndent().toContentList(), null - ) - ) - ) - val response = api.chat( - chatRequest, - AppSettingsState.instance.smartModel.chatModel() - ).choices.first().message?.content?.trim() ?: "" - var outputPath = basePath - val header = response.lines().first() - var body = response.lines().drop(1).joinToString("\n").trim().lines().dropWhile { it.startsWith("```") }.dropLastWhile { it.startsWith("```") }.joinToString("\n") - val pathPattern = """File(?:name)?: ['`"]?([^'`"]+)['`"]?""".toRegex() - if (pathPattern.matches(header)) { - val match = pathPattern.matchEntire(header)!! - outputPath = match.groupValues[1] - } - return ProjectFile( - path = outputPath, - code = body - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateImageAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateImageAction.kt deleted file mode 100644 index f197f582..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/CreateImageAction.kt +++ /dev/null @@ -1,254 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import ai.grazie.utils.mpp.UUID -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.MultiStepPatchAction.AutoDevApp.Settings -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.AppSettingsState.Companion.imageModel -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.ChatClient -import com.simiacryptus.jopenai.models.ApiModel -import com.simiacryptus.jopenai.models.ApiModel.Role -import com.simiacryptus.jopenai.models.ChatModel -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import com.simiacryptus.skyenet.Discussable -import com.simiacryptus.skyenet.core.actors.* -import com.simiacryptus.skyenet.core.platform.* -import com.simiacryptus.skyenet.core.platform.file.DataStorage -import com.simiacryptus.skyenet.core.platform.model.StorageInterface -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.core.util.getModuleRootForFile -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import org.slf4j.LoggerFactory -import java.io.ByteArrayOutputStream -import java.io.File -import java.nio.file.Path -import java.util.concurrent.Semaphore -import java.util.concurrent.atomic.AtomicReference -import javax.imageio.ImageIO - -class CreateImageAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - val path = "/imageCreator" - - override fun handle(event: AnActionEvent) { - var root: Path? = null - val codeFiles: MutableSet = mutableSetOf() - - fun codeSummary() = codeFiles.filter { - root!!.resolve(it).toFile().exists() - }.associateWith { root!!.resolve(it).toFile().readText(Charsets.UTF_8) } - .entries.joinToString("\n\n") { (path, code) -> - val extension = path.toString().split('.').lastOrNull()?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ } - """ - |# $path - |```$extension - |${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} - |``` - """.trimMargin() - } - - val dataContext = event.dataContext - val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) - val folder = UITools.getSelectedFolder(event) - root = if (null != folder) { - folder.toFile.toPath() - } else if (1 == virtualFiles?.size) { - UITools.getSelectedFile(event)?.parent?.toNioPath() - } else { - getModuleRootForFile(UITools.getSelectedFile(event)?.parent?.toFile ?: throw RuntimeException("")).toPath() - } - - val files = getFiles(virtualFiles, root!!) - codeFiles.addAll(files) - - val session = Session.newGlobalID() -// val storage = ApplicationServices.dataStorageFactory(root?.toFile()!!) as DataStorage? -// val selectedFile = UITools.getSelectedFolder(event) - if (/*null != storage &&*/ null != root) { - DataStorage.sessionPaths[session] = root.toFile()!! - } - - SessionProxyServer.chats[session] = PatchApp(event, root.toFile(), ::codeSummary) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(event.project) - - Thread { - Thread.sleep(500) - try { - - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - inner class PatchApp( - private val event: AnActionEvent, - override val root: File, - val codeSummary: () -> String = { "" }, - ) : ApplicationServer( - applicationName = "Multi-file Patch Chat", - path = path, - showMenubar = false, - ) { - override val singleInput = false - override val stickyInput = true - - override fun userMessage( - session: Session, - user: User?, - userMessage: String, - ui: ApplicationInterface, - api: API - ) { - val settings = getSettings(session, user) ?: Settings() - if (api is ChatClient) api.budget = settings.budget ?: 2.00 - PatchAgent( - api = api, - dataStorage = dataStorage, - session = session, - user = user, - ui = ui, - model = settings.model!!, - codeSummary = { codeSummary() }, - event = event, - root = root, - ).start( - userMessage = userMessage, - ) - } - } - - enum class ActorTypes { - MainActor, - } - - inner class PatchAgent( - val api: API, - dataStorage: StorageInterface, - session: Session, - user: User?, - val ui: ApplicationInterface, - val model: ChatModel, - val codeSummary: () -> String = { "" }, - actorMap: Map> = mapOf( - ActorTypes.MainActor to ImageActor( - prompt = """ - |You are a technical drawing assistant. - | - |You will be composing an image about the following code: - | - |${codeSummary()} - | - """.trimMargin(), - textModel = model, - imageModel = AppSettingsState.instance.mainImageModel.imageModel() - ), - ), - val event: AnActionEvent, - val root: File, - ) : ActorSystem( - actorMap.map { it.key.name to it.value }.toMap(), dataStorage, user, session - ) { - - private val mainActor by lazy { getActor(ActorTypes.MainActor) as ImageActor } - - fun start( - userMessage: String, - ) { - val task = ui.newTask() - val toInput = { it: String -> listOf(codeSummary(), it) } - Discussable( - task = task, - userMessage = { userMessage }, - heading = userMessage, - initialResponse = { it: String -> mainActor.answer(toInput(it), api = api) }, - outputFn = { img: ImageResponse -> - val id = UUID.random().text - renderMarkdown( - "", ui = ui - ) - }, - ui = ui, - reviseResponse = { userMessages: List> -> - mainActor.respond( - messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } - .toTypedArray()), - input = toInput(userMessage), - api = api - ) - }, - atomicRef = AtomicReference(), - semaphore = Semaphore(0), - ).call() - } - } - - private fun write( - code: ImageResponse, - path: Path - ): ByteArray { - val byteArrayOutputStream = ByteArrayOutputStream() - val data = ImageIO.write( - code.image, - path.toString().split(".").last(), - byteArrayOutputStream - ) - val bytes = byteArrayOutputStream.toByteArray() - return bytes - } - - private fun getFiles( - virtualFiles: Array?, - root: Path - ): MutableSet { - val codeFiles = mutableSetOf() - virtualFiles?.forEach { file -> - if (file.isDirectory) { - getFiles(file.children, root) - } else { - val relative = root.relativize(file.toNioPath()) - codeFiles.add(relative) //[] = file.contentsToByteArray().toString(Charsets.UTF_8) - } - } - return codeFiles - } - - override fun isEnabled(event: AnActionEvent) = true - - companion object { - private val log = LoggerFactory.getLogger(CreateImageAction::class.java) - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DiffChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DiffChatAction.kt deleted file mode 100644 index 121f9794..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/DiffChatAction.kt +++ /dev/null @@ -1,151 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.CodeChatSocketManager -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.command.WriteCommandAction -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.intellij.openapi.util.TextRange -import com.simiacryptus.diff.addApplyDiffLinks -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.session.SessionTask -import org.intellij.lang.annotations.Language -import org.slf4j.LoggerFactory - -class DiffChatAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - val path = "/diffChat" - - override fun handle(e: AnActionEvent) { - val editor = e.getData(CommonDataKeys.EDITOR) ?: return - val session = Session.newGlobalID() - val language = ComputerLanguage.getComputerLanguage(e)?.name ?: "" - val document = editor.document - val filename = FileDocumentManager.getInstance().getFile(document)?.name ?: return - val primaryCaret = editor.caretModel.primaryCaret - val rawText: String - val selectionStart: Int - var selectionEnd: Int - val selectedText = primaryCaret.selectedText - if (null != selectedText) { - rawText = selectedText - selectionStart = primaryCaret.selectionStart - selectionEnd = primaryCaret.selectionEnd - } else { - rawText = document.text - selectionStart = 0 - selectionEnd = rawText.length - } - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - SessionProxyServer.agents[session] = object : CodeChatSocketManager( - session = session, - language = language, - codeSelection = rawText, - filename = filename, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) - ) { - override val systemPrompt: String - @Language("Markdown") - get() = super.systemPrompt + """ - |Please provide code modifications in the following diff format within triple-backtick diff code blocks. Each diff block should be preceded by a header that identifies the file being modified. - | - |The diff format rules are as follows: - |- Use '-' at the beginning of a line to indicate a deletion. - |- Use '+' at the beginning of a line to indicate an addition. - |- Include 2 lines of context before and after every change to help identify the location of the change. - |- If a line is part of the original code and hasn't been modified, simply include it without '+' or '-'. - |- Lines starting with "@@" or "---" or "+++" are treated as headers and are ignored. - | - |Example: - | - |Here are the patches: - | - |### src/utils/exampleUtils.js - |```diff - | // Utility functions for example feature - | const b = 2; - | function exampleFunction() { - |- return b + 1; - |+ return b + 2; - | } - |``` - | - |### tests/exampleUtils.test.js - |```diff - | // Unit tests for exampleUtils - | const assert = require('assert'); - | const { exampleFunction } = require('../src/utils/exampleUtils'); - | - | describe('exampleFunction', () => { - |- it('should return 3', () => { - |+ it('should return 4', () => { - | assert.equal(exampleFunction(), 3); - | }); - | }); - |``` - - """.trimMargin() - - val ui by lazy { ApplicationInterface(this) } - override fun renderResponse(response: String, task: SessionTask) = """
${ - renderMarkdown( - addApplyDiffLinks( - code = { - editor.document.getText(TextRange(selectionStart, selectionEnd)) - }, - response = response, - handle = { newCode: String -> - WriteCommandAction.runWriteCommandAction(e.project) { - selectionEnd = selectionStart + newCode.length - document.replaceString(selectionStart, selectionStart + rawText.length, newCode) - } - }, - task = task, - ui = ui - ) - ) - }
""" - } - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - override fun isEnabled(event: AnActionEvent) = true - - companion object { - private val log = LoggerFactory.getLogger(DiffChatAction::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateDocumentationAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateDocumentationAction.kt deleted file mode 100644 index 5fdb88c3..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateDocumentationAction.kt +++ /dev/null @@ -1,424 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.actions.FileContextAction -import com.github.simiacryptus.aicoder.actions.test.TestResultAutofixAction -import com.github.simiacryptus.aicoder.actions.test.TestResultAutofixAction.Companion.getProjectStructure -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.Name -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.openapi.ui.Messages -import com.intellij.openapi.vfs.LocalFileSystem -import com.intellij.ui.CheckBoxList -import com.intellij.ui.components.JBScrollPane -import com.intellij.ui.components.JBTextArea -import com.intellij.ui.components.JBTextField -import com.simiacryptus.jopenai.models.ApiModel -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import org.apache.commons.io.IOUtils -import java.awt.BorderLayout -import java.awt.Dimension -import java.io.File -import java.io.FileInputStream -import java.nio.file.Files -import java.nio.file.Path -import java.util.TreeMap -import java.util.concurrent.Executors -import java.util.concurrent.Future -import java.util.concurrent.TimeUnit -import java.util.concurrent.TimeoutException -import javax.swing.* -import javax.swing.JComboBox - - -class GenerateDocumentationAction : FileContextAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent): Boolean { - if (UITools.getSelectedFile(event)?.isDirectory == false) return false - return super.isEnabled(event) - } - - class SettingsUI { - @Name("Single Output File") - val singleOutputFile = JCheckBox("Produce a single output file", true) - - @Name("Files to Process") - val filesToProcess = CheckBoxList() - - @Name("AI Instruction") - val transformationMessage = JBTextArea(4, 40) - - @Name("Recent Instructions") - val recentInstructions = JComboBox() - - @Name("Output File") - val outputFilename = JBTextField() - - @Name("Output Directory") - val outputDirectory = JBTextField() - } - - class UserSettings( - var transformationMessage: String = "Create user documentation", - var outputFilename: String = "compiled_documentation.md", - var filesToProcess: List = listOf(), - var singleOutputFile: Boolean = true, - var outputDirectory: String = "docs/" - ) - - class Settings( - val settings: UserSettings? = null, - val project: Project? = null - ) - - override fun getConfig(project: Project?, e: AnActionEvent): Settings? { - val root = UITools.getSelectedFolder(e)?.toNioPath() - val files = Files.walk(root) - .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } - .toList().filterNotNull().sortedBy { it.toString() }.toTypedArray() - val settingsUI = SettingsUI().apply { - filesToProcess.setItems(files.toMutableList()) { path -> - root?.relativize(path)?.toString() ?: path.toString() - } - files.forEach { path -> - filesToProcess.setItemSelected(path, true) - } - outputDirectory.text = "docs/" - } - val mruDocumentationInstructions = AppSettingsState.instance.getRecentCommands("DocumentationInstructions") - settingsUI.recentInstructions.model = DefaultComboBoxModel( - mruDocumentationInstructions.getMostRecent(10).map { - "${it.split(" ").first()} ${it.split(" ").drop(1).joinToString(" ")}" - }.toTypedArray() - ) - settingsUI.recentInstructions.selectedIndex = -1 - settingsUI.recentInstructions.addActionListener { updateUIFromSelection(settingsUI) } - val dialog = DocumentationCompilerDialog(project, settingsUI) - dialog.show() - val settings: UserSettings = dialog.userSettings - settings.singleOutputFile = settingsUI.singleOutputFile.isSelected - settings.outputDirectory = settingsUI.outputDirectory.text - val result = dialog.isOK - settings.filesToProcess = when { - result -> files.filter { path -> settingsUI.filesToProcess.isItemSelected(path) }.sortedBy { it.toString() }.toList() - else -> listOf() - } - if (settings.filesToProcess.isEmpty()) return null - mruDocumentationInstructions.addInstructionToHistory("${settings.outputFilename} ${settings.transformationMessage}") - //.map { path -> return@map root?.resolve(path) }.filterNotNull() - return Settings(settings, project) - } - - private fun updateUIFromSelection(settingsUI: SettingsUI) { - val selected = settingsUI.recentInstructions.selectedItem as? String - if (selected != null) { - val parts = selected.split(" ", limit = 2) - if (parts.size == 2) { - settingsUI.outputFilename.text = parts[0] - settingsUI.transformationMessage.text = parts[1] - } else { - settingsUI.transformationMessage.text = selected - } - } - } - - override fun processSelection(state: SelectionState, config: Settings?, progress: ProgressIndicator): Array { - progress.fraction = 0.0 - if (config?.settings == null) { - // Dialog was cancelled, return empty array - return emptyArray().also { - // Ensure we don't attempt to open any files when dialog is cancelled - return@also - } - } - progress.text = "Initializing documentation generation..." - - val selectedFolder = state.selectedFile.toPath() - val gitRoot = TestResultAutofixAction.findGitRoot(selectedFolder) ?: selectedFolder - val outputDirectory = config.settings.outputDirectory - var outputPath = - selectedFolder.resolve(config.settings.outputFilename) - val relativePath = gitRoot.relativize(outputPath) - outputPath = gitRoot.resolve(outputDirectory).resolve(relativePath) - if (outputPath.toFile().exists()) { - val extension = outputPath.toString().split(".").last() - val name = outputPath.toString().split(".").dropLast(1).joinToString(".") - val fileIndex = (1..Int.MAX_VALUE).find { - !selectedFolder.resolve("$name.$it.$extension").toFile().exists() - } - outputPath = selectedFolder.resolve("$name.$fileIndex.$extension") - } - val executorService = Executors.newFixedThreadPool(4) - val transformationMessage = config.settings.transformationMessage - val markdownContent = TreeMap() - try { - val selectedPaths = config.settings.filesToProcess.sortedBy { it.toString() } - val partitionedPaths = Files.walk(selectedFolder) - .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } - .toList().sortedBy { it.toString() }.groupBy { selectedPaths.contains(it) } - val totalFiles = partitionedPaths[true]?.size ?: 0 - var processedFiles = 0 - val pathList = partitionedPaths[true] - ?.toList()?.filterNotNull() - ?.map> { path -> - executorService.submit { - var retries = 0 - val maxRetries = 3 - while (retries < maxRetries) { - try { - val fileContent = - IOUtils.toString(FileInputStream(path.toFile()), "UTF-8") ?: return@submit null - val transformContent = transformContent(path, fileContent, transformationMessage) - processTransformedContent( - path, - transformContent, - config, - selectedFolder, - gitRoot, - outputDirectory, - outputPath, - markdownContent - ) - synchronized(progress) { - processedFiles++ - progress.fraction = processedFiles.toDouble() / totalFiles - progress.text = "Processing file ${processedFiles} of ${totalFiles}" - } - return@submit path - } catch (e: Exception) { - retries++ - if (retries >= maxRetries) { - log.error("Failed to process file after $maxRetries attempts: $path", e) - return@submit null - } - log.warn("Error processing file: $path. Retrying (attempt $retries)", e) - Thread.sleep(1000L * retries) // Exponential backoff - } - } - null - } - }?.toTypedArray()?.map { future -> - try { - future.get(2, TimeUnit.MINUTES) // Set a timeout for each file processing - } catch (e: Exception) { - when (e) { - is TimeoutException -> log.error("File processing timed out", e) - else -> log.error("Error processing file", e) - } - null - } - }?.filterNotNull() ?: listOf() - if (config.settings.singleOutputFile == true) { - val sortedContent = markdownContent.entries.joinToString("\n\n") { (path, content) -> - "# $path\n\n$content" - } - outputPath.parent.toFile().mkdirs() - outputPath.parent.toFile().mkdirs() - Files.write(outputPath, sortedContent.toByteArray()) - open(config.project!!, outputPath) - return arrayOf(outputPath.toFile()) - } else { - val outputDir = selectedFolder.resolve(outputDirectory) - outputDir.toFile().mkdirs() - open(config.project!!, selectedFolder.resolve(outputDirectory)) - return pathList.map { it.toFile() }.toTypedArray() - } - } finally { - executorService.shutdown() - } - } - - private fun processTransformedContent( - path: Path, - transformContent: String, - config: Settings?, - selectedFolder: Path, - gitRoot: Path, - outputDirectory: String, - outputPath: Path, - markdownContent: TreeMap - ) { - if (config?.settings?.singleOutputFile == true) { - markdownContent[selectedFolder.relativize(path).toString()] = transformContent.replace("(?s)(? Unit - function = { - val file = outputPath.toFile() - if (file.exists()) { - // Ensure the IDE is ready for file operations - ApplicationManager.getApplication().invokeLater { - val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) - if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { - val localFileSystem = LocalFileSystem.getInstance() - // Refresh the file system to ensure the file is visible - val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) - virtualFile?.let { - FileEditorManager.getInstance(project).openFile(it, true) - } ?: scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } else { - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - } else { - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - } - - inner class DocumentationCompilerDialog(project: Project?, private val settingsUI: SettingsUI) : DialogWrapper(project) { - val userSettings = UserSettings() - - init { - title = "Compile Documentation" - // Set the default values for the UI elements from userSettings - settingsUI.transformationMessage.text = userSettings.transformationMessage - settingsUI.outputFilename.text = userSettings.outputFilename - settingsUI.outputDirectory.text = userSettings.outputDirectory - settingsUI.singleOutputFile.isSelected = userSettings.singleOutputFile - settingsUI.recentInstructions.addActionListener { - val selected = settingsUI.recentInstructions.selectedItem as? String - selected?.let { - updateUIFromSelection(settingsUI) - } - } - init() - } - - override fun createCenterPanel(): JComponent { - val panel = JPanel(BorderLayout()).apply { - val filesScrollPane = JBScrollPane(settingsUI.filesToProcess).apply { - preferredSize = Dimension(600, 400) // Increase the size for better visibility - } - add(filesScrollPane, BorderLayout.CENTER) // Make the files list the dominant element - - val optionsPanel = JPanel().apply { - layout = BoxLayout(this, BoxLayout.Y_AXIS) - border = BorderFactory.createEmptyBorder(10, 10, 10, 10) // Add some padding - add(JLabel("Recent Instructions")) - add(settingsUI.recentInstructions) - add(Box.createVerticalStrut(10)) - add(JLabel("AI Instruction")) - add(settingsUI.transformationMessage) - add(Box.createVerticalStrut(10)) - add(Box.createVerticalStrut(10)) // Add some vertical spacing - add(JLabel("Output File")) - add(settingsUI.outputFilename) - add(Box.createVerticalStrut(10)) - add(JLabel("Output Directory")) - add(settingsUI.outputDirectory) - add(Box.createVerticalStrut(10)) - add(settingsUI.singleOutputFile) - } - add(optionsPanel, BorderLayout.SOUTH) - } - return panel - } - - override fun doOKAction() { - if (!validateInput()) { - return - } - super.doOKAction() - userSettings.transformationMessage = settingsUI.transformationMessage.text - userSettings.outputFilename = settingsUI.outputFilename.text - userSettings.outputDirectory = settingsUI.outputDirectory.text - // Assuming filesToProcess already reflects the user's selection -// userSettings.filesToProcess = settingsUI.filesToProcess.selectedValuesList - userSettings.filesToProcess = - settingsUI.filesToProcess.items.filter { path -> settingsUI.filesToProcess.isItemSelected(path) } - userSettings.singleOutputFile = settingsUI.singleOutputFile.isSelected - } - - private fun validateInput(): Boolean { - if (settingsUI.transformationMessage.text.isBlank()) { - Messages.showErrorDialog("AI Instruction cannot be empty", "Input Error") - return false - } - if (settingsUI.outputFilename.text.isBlank()) { - Messages.showErrorDialog("Output File cannot be empty", "Input Error") - return false - } - if (settingsUI.outputDirectory.text.isBlank()) { - Messages.showErrorDialog("Output Directory cannot be empty", "Input Error") - return false - } - return true - } - } -} - -val CheckBoxList.items: List - get() { - val items = mutableListOf() - for (i in 0 until model.size) { - items.add(getItemAt(i)!!) - } - return items - } \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateRelatedFileAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateRelatedFileAction.kt deleted file mode 100644 index 8be7b82c..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenerateRelatedFileAction.kt +++ /dev/null @@ -1,172 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.actions.FileContextAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.Name -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.LocalFileSystem -import com.simiacryptus.jopenai.models.ApiModel -import com.simiacryptus.jopenai.models.ApiModel.ChatMessage -import com.simiacryptus.jopenai.models.ApiModel.Role -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import com.simiacryptus.skyenet.core.util.getModuleRootForFile -import org.apache.commons.io.FileUtils -import org.apache.commons.io.IOUtils -import java.io.File -import java.io.FileInputStream -import java.nio.file.Path -import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicReference -import javax.swing.JTextArea - -class GenerateRelatedFileAction : FileContextAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - override fun isEnabled(event: AnActionEvent): Boolean { - return UITools.getSelectedFiles(event).size == 1 && super.isEnabled(event) - } - - data class ProjectFile( - val path: String = "", - val code: String = "" - ) - - class SettingsUI { - @Name("Directive") - var directive: JTextArea = JTextArea( - """ - Create test cases - """.trimIndent(), - 3, - 120 - ) - } - - class UserSettings( - var directive: String = "", - ) - - class Settings( - val settings: UserSettings? = null, - val project: Project? = null - ) - - override fun getConfig(project: Project?, e: AnActionEvent): Settings { - return Settings( - UITools.showDialog( - project, - SettingsUI::class.java, - UserSettings::class.java, - "Create Analogue File" - ), project - ) - } - - override fun processSelection(state: SelectionState, config: Settings?, progress: ProgressIndicator): Array { - val root = getModuleRootForFile(state.selectedFile).toPath() - val selectedFile = state.selectedFile - val analogue = generateFile( - ProjectFile( - path = root.relativize(selectedFile.toPath()).toString(), - code = IOUtils.toString(FileInputStream(selectedFile), "UTF-8") - ), - config?.settings?.directive ?: "" - ) - var outputPath = root.resolve(analogue.path) - if (outputPath.toFile().exists()) { - val extension = outputPath.toString().split(".").last() - val name = outputPath.toString().split(".").dropLast(1).joinToString(".") - val fileIndex = (1..Int.MAX_VALUE).find { - !root.resolve("$name.$it.$extension").toFile().exists() - } - outputPath = root.resolve("$name.$fileIndex.$extension") - } - outputPath.parent.toFile().mkdirs() - FileUtils.write(outputPath.toFile(), analogue.code, "UTF-8") - open(config?.project!!, outputPath) - return arrayOf(outputPath.toFile()) - } - - private fun generateFile(baseFile: ProjectFile, directive: String): ProjectFile { - val model = AppSettingsState.instance.smartModel.chatModel() - val chatRequest = ApiModel.ChatRequest( - model = model.modelName, - temperature = AppSettingsState.instance.temperature, - messages = listOf( - ChatMessage( - Role.system, """ - You will combine natural language instructions with a user provided code example to create a new file. - Provide a new filename and the code to be written to the file. - Paths should be relative to the project root and should not exist. - Output the file path using the a line with the format "File: ". - Output the file code directly after the header line with no additional decoration. - """.trimIndent().toContentList(), null - ), - ChatMessage( - Role.user, """ - |Create a new file based on the following directive: $directive - | - |The file should be based on `${baseFile.path}` which contains the following code: - | - |``` - |${baseFile.code.let { /*escapeHtml4*/it/*.indent(" ")*/ }} - |``` - """.trimMargin().toContentList(), null - ) - - ) - ) - val response = api.chat(chatRequest, model).choices.firstOrNull()?.message?.content?.trim() ?: throw IllegalStateException("No response from API") - var outputPath = baseFile.path - val header = response?.split("\n")?.first() - var body = response?.split("\n")?.drop(1)?.joinToString("\n")?.trim() - if (body?.contains("```") == true) { - body = body.split("```.*".toRegex()).drop(1).firstOrNull()?.trim() ?: body - } - val pathPattern = "File(?:name)?: ['\"]?([^'\"]+)['\"]?".toRegex() - val matcher = pathPattern.find(header ?: "") - if (matcher != null) { - outputPath = matcher.groupValues[1].trim() - } - return ProjectFile( - path = outputPath, - code = body ?: "" - ) - } - - companion object { - fun open(project: Project, outputPath: Path) { - val functionRef = AtomicReference<(() -> Unit)?>(null) - val function: () -> Unit = { - val file = outputPath.toFile() - if (file.exists()) { - // Ensure the IDE is ready for file operations - ApplicationManager.getApplication().invokeLater { - val ioFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) - if (false == (ioFile?.let { FileEditorManager.getInstance(project).isFileOpen(it) })) { - val localFileSystem = LocalFileSystem.getInstance() - // Refresh the file system to ensure the file is visible - val virtualFile = localFileSystem.refreshAndFindFileByIoFile(file) - virtualFile?.let { - FileEditorManager.getInstance(project).openFile(it, true) - } ?: scheduledPool.schedule(functionRef.get()!!, 100, TimeUnit.MILLISECONDS) - } else { - scheduledPool.schedule(functionRef.get()!!, 100, TimeUnit.MILLISECONDS) - } - } - } else { - scheduledPool.schedule(functionRef.get()!!, 100, TimeUnit.MILLISECONDS) - } - } - functionRef.set(function) - scheduledPool.schedule(function, 100, TimeUnit.MILLISECONDS) - } - - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenericChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenericChatAction.kt deleted file mode 100644 index 9902142f..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/GenericChatAction.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.chat.ChatSocketManager -import org.slf4j.LoggerFactory - -class GenericChatAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - val path = "/codeChat" - val systemPrompt = "" - val userInterfacePrompt = "" - val model = AppSettingsState.instance.smartModel.chatModel() - - override fun handle(e: AnActionEvent) { - val session = Session.newGlobalID() - SessionProxyServer.agents[session] = ChatSocketManager( - session = session, - model = model, - initialAssistantPrompt = "", - userInterfacePrompt = userInterfacePrompt, - systemPrompt = systemPrompt, - api = api, - storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome), - applicationClass = ApplicationServer::class.java, - ) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - override fun isEnabled(event: AnActionEvent) = true - - companion object { - private val log = LoggerFactory.getLogger(CodeChatAction::class.java) - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MassPatchAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MassPatchAction.kt deleted file mode 100644 index 3f9784fd..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MassPatchAction.kt +++ /dev/null @@ -1,339 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.MassPatchAction.Settings -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.Name -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.ui.CheckBoxList -import com.intellij.ui.components.JBScrollPane -import com.intellij.ui.components.JBTextArea -import com.simiacryptus.diff.FileValidationUtils.Companion.isLLMIncludableFile -import com.simiacryptus.diff.addApplyFileDiffLinks -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.ChatClient -import com.simiacryptus.jopenai.models.ApiModel -import com.simiacryptus.jopenai.models.ApiModel.Role -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import com.simiacryptus.skyenet.Discussable -import com.simiacryptus.skyenet.TabbedDisplay -import com.simiacryptus.skyenet.core.actors.SimpleActor -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager -import com.simiacryptus.skyenet.webui.session.SocketManager -import java.awt.BorderLayout -import java.awt.Dimension -import java.nio.file.Files -import java.nio.file.Path -import java.util.UUID -import java.util.concurrent.Semaphore -import java.util.concurrent.atomic.AtomicReference -import javax.swing.Box -import javax.swing.BoxLayout -import javax.swing.DefaultComboBoxModel -import javax.swing.JComboBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JCheckBox - -class MassPatchAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - override fun isEnabled(event: AnActionEvent): Boolean { - if (UITools.getSelectedFile(event)?.isDirectory == false) return false - return super.isEnabled(event) - } - - class SettingsUI { - @Name("Files to Process") - val filesToProcess = CheckBoxList() - - @Name("AI Instruction") - val transformationMessage = JBTextArea(4, 40) - - @Name("Recent Instructions") - val recentInstructions = JComboBox() - @Name("Auto Apply") - val autoApply = JCheckBox("Auto Apply Changes") - - } - - class UserSettings( - var transformationMessage: String = "Review, fix, and improve", - var filesToProcess: List = listOf(), - var autoApply: Boolean = false, - ) - - class Settings( - val settings: UserSettings? = null, - val project: Project? = null, - ) - - fun getConfig(project: Project?, e: AnActionEvent): Settings? { - val root = UITools.getSelectedFolder(e)?.toNioPath() - val files = Files.walk(root) - .filter { isLLMIncludableFile(it.toFile()) } - .toList().filterNotNull().toTypedArray() - val settingsUI = SettingsUI().apply { - filesToProcess.setItems(files.toMutableList()) { path -> - root?.relativize(path)?.toString() ?: path.toString() - } - files.forEach { path -> - filesToProcess.setItemSelected(path, true) - } - autoApply.isSelected = false - } - val mruPatchInstructions = AppSettingsState.instance.getRecentCommands("PatchInstructions") - settingsUI.recentInstructions.model = DefaultComboBoxModel( - mruPatchInstructions.getMostRecent(10).toTypedArray() - ) - settingsUI.recentInstructions.selectedIndex = -1 - settingsUI.recentInstructions.addActionListener { - updateUIFromSelection(settingsUI) - } - - val dialog = ConfigDialog(project, settingsUI, "Mass Patch") - dialog.show() - if (!dialog.isOK) return null - val settings: UserSettings = dialog.userSettings - settings.filesToProcess = files.filter { path -> settingsUI.filesToProcess.isItemSelected(path) }.toList() - mruPatchInstructions.addInstructionToHistory(settings.transformationMessage) - return Settings(settings, project) - } - - private fun updateUIFromSelection(settingsUI: SettingsUI) { - val selected = settingsUI.recentInstructions.selectedItem as? String - if (selected != null) { - settingsUI.transformationMessage.text = selected - } - } - - - override fun handle(e: AnActionEvent) { - val project = e.project - val config = getConfig(project, e) - - val session = Session.newGlobalID() - SessionProxyServer.chats[session] = MassPatchServer(config=config!!, api=api, autoApply = config.settings?.autoApply ?: false) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(e.project) - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - - } - - class ConfigDialog(project: Project?, private val settingsUI: SettingsUI, title: String) : DialogWrapper(project) { - val userSettings = UserSettings() - - init { - this.title = title - // Set the default values for the UI elements from userSettings - settingsUI.transformationMessage.text = userSettings.transformationMessage - settingsUI.autoApply.isSelected = userSettings.autoApply - init() - } - - override fun createCenterPanel(): JComponent { - val panel = JPanel(BorderLayout()).apply { - val filesScrollPane = JBScrollPane(settingsUI.filesToProcess).apply { - preferredSize = Dimension(400, 300) // Adjust the preferred size as needed - } - add(JLabel("Files to Process"), BorderLayout.NORTH) - add(filesScrollPane, BorderLayout.CENTER) // Make the files list the dominant element - - val optionsPanel = JPanel().apply { - layout = BoxLayout(this, BoxLayout.Y_AXIS) - add(JLabel("Recent Instructions")) - add(settingsUI.recentInstructions) - add(Box.createVerticalStrut(10)) - add(JLabel("AI Instruction")) - add(settingsUI.transformationMessage) - add(Box.createVerticalStrut(10)) - add(settingsUI.autoApply) - } - add(optionsPanel, BorderLayout.SOUTH) - } - return panel - } - - override fun doOKAction() { - super.doOKAction() - userSettings.transformationMessage = settingsUI.transformationMessage.text - userSettings.filesToProcess = - settingsUI.filesToProcess.items.filter { path -> settingsUI.filesToProcess.isItemSelected(path) } - userSettings.autoApply = settingsUI.autoApply.isSelected - } - } -} - -class MassPatchServer( - val config: Settings, - val api: ChatClient, - val autoApply: Boolean -) : ApplicationServer( - applicationName = "Multi-file Patch Chat", - path = "/patchChat", - showMenubar = false, -) { - private lateinit var _root: Path - - - override val singleInput = false - override val stickyInput = true - private val mainActor: SimpleActor - get() { - - return SimpleActor( - prompt = """ - |You are a helpful AI that helps people with coding. - | - |Response should use one or more code patches in diff format within ```diff code blocks. - |Each diff should be preceded by a header that identifies the file being modified. - |The diff format should use + for line additions, - for line deletions. - |The diff should include 2 lines of context before and after every change. - | - |Example: - | - |Here are the patches: - | - |### src/utils/exampleUtils.js - |```diff - | // Utility functions for example feature - | const b = 2; - | function exampleFunction() { - |- return b + 1; - |+ return b + 2; - | } - |``` - | - |### tests/exampleUtils.test.js - |```diff - | // Unit tests for exampleUtils - | const assert = require('assert'); - | const { exampleFunction } = require('../src/utils/exampleUtils'); - | - | describe('exampleFunction', () => { - |- it('should return 3', () => { - |+ it('should return 4', () => { - | assert.equal(exampleFunction(), 3); - | }); - | }); - |``` - | - |If needed, new files can be created by using code blocks labeled with the filename in the same manner. - """.trimMargin(), - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - ) - } - - override fun newSession(user: User?, session: Session): SocketManager { - val socketManager = super.newSession(user, session) - val ui = (socketManager as ApplicationSocketManager).applicationInterface - _root = config.project?.basePath?.let { Path.of(it) } ?: Path.of(".") - val task = ui.newTask(true) - val api = (api as ChatClient).getChildClient().apply { - val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") - createFile.second?.apply { - logStreams += this.outputStream().buffered() - task.verbose("API log: $this") - } - } - val tabs = TabbedDisplay(task) - val userMessage = config.settings?.transformationMessage ?: "Create user documentation" - val codeFiles = config.settings?.filesToProcess - codeFiles?.forEach { path -> - socketManager.scheduledThreadPoolExecutor.schedule({ - socketManager.pool.submit { - try { - val codeSummary = listOf(path) - .filter { isLLMIncludableFile(it.toFile()) } - ?.associateWith { it.toFile().readText(Charsets.UTF_8) } - ?.entries?.joinToString("\n\n") { (path, code) -> - val extension = path.toString().split('.').lastOrNull() - """ - |# $path - |```$extension - |${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} - |``` - """.trimMargin() - } - val fileTask = ui.newTask(false).apply { - tabs[path.toString()] = placeholder - } - val toInput = { it: String -> listOf(codeSummary ?: "", it) } - Discussable( - task = fileTask, - userMessage = { userMessage }, - heading = renderMarkdown(userMessage), - initialResponse = { - mainActor.answer(toInput(it), api = api) - }, - outputFn = { design: String -> - var markdown = ui.socketManager?.addApplyFileDiffLinks( - root = _root, - response = design, - handle = { newCodeMap: Map -> - newCodeMap.forEach { (path, newCode) -> - fileTask.complete("$path Updated") - } - }, - ui = ui, - api = api as API, - shouldAutoApply = { autoApply }, - model = AppSettingsState.instance.fastModel.chatModel(), - ) - """
${renderMarkdown(markdown!!)}
""" - }, - ui = ui, - reviseResponse = { userMessages: List> -> - mainActor.respond( - messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } - .toTypedArray()), - input = toInput(userMessage), - api = api - ) - }, - atomicRef = AtomicReference(), - semaphore = Semaphore(0), - ).call() - } catch (e: Exception) { - log.warn("Error processing $path", e) - task.error(ui, e) - } - } - }, 10, java.util.concurrent.TimeUnit.MILLISECONDS) - } - return socketManager - } - - companion object { - val log = org.slf4j.LoggerFactory.getLogger(MassPatchServer::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiCodeChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiCodeChatAction.kt deleted file mode 100644 index c7e8cb8c..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiCodeChatAction.kt +++ /dev/null @@ -1,189 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.MultiStepPatchAction.AutoDevApp.Settings -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.diff.addApplyFileDiffLinks -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.ChatClient -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.util.GPT4Tokenizer -import com.simiacryptus.skyenet.Retryable -import com.simiacryptus.skyenet.core.actors.SimpleActor -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.core.util.getModuleRootForFile -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import org.slf4j.LoggerFactory -import java.io.File -import java.nio.file.Path -import java.util.UUID - -class MultiCodeChatAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(event: AnActionEvent) { - var root: Path? = null - val codeFiles: MutableSet = mutableSetOf() - fun codeSummary() = codeFiles.filter { - root!!.resolve(it).toFile().exists() - }.associateWith { root!!.resolve(it).toFile().readText(Charsets.UTF_8) } - .entries.joinToString("\n\n") { (path, code) -> - val extension = path.toString().split('.').lastOrNull()?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ } - """ - |# $path - |```$extension - |${code} - |``` - """.trimMargin() - } - - val dataContext = event.dataContext - val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) - val folder = UITools.getSelectedFolder(event) - root = if (null != folder) { - folder.toFile.toPath() - } else { - getModuleRootForFile(UITools.getSelectedFile(event)?.parent?.toFile ?: throw RuntimeException("")).toPath() - } - val files = getFiles(virtualFiles, root!!) - codeFiles.addAll(files) - - val session = Session.newGlobalID() - SessionProxyServer.chats[session] = PatchApp(root.toFile(), { codeSummary() }, codeFiles) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - val server = AppServer.getServer(event.project) - - Thread { - Thread.sleep(500) - try { - - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - inner class PatchApp( - override val root: File, - val codeSummary: () -> String, - val codeFiles: Set = setOf(), - ) : ApplicationServer( - applicationName = "Multi-file Patch Chat", - path = "/patchChat", - showMenubar = false, - ) { - override val singleInput = false - override val stickyInput = true - private val mainActor: SimpleActor - get() = SimpleActor( - prompt = """ - |You are a helpful AI that helps people with coding. - | - |You will be answering questions about the following code: - | - |${codeSummary()} - | - """.trimMargin(), - model = AppSettingsState.instance.smartModel.chatModel() - ) - - override fun userMessage( - session: Session, - user: User?, - userMessage: String, - ui: ApplicationInterface, - api: API - ) { - val settings = getSettings(session, user) ?: Settings() - if (api is ChatClient) api.budget = settings.budget ?: 2.00 - - val task = ui.newTask() - val codex = GPT4Tokenizer() - - val api = (api as ChatClient).getChildClient().apply { - val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") - createFile.second?.apply { - logStreams += this.outputStream().buffered() - task.verbose("API log: $this") - } - } - task.echo(renderMarkdown(userMessage)) - task.verbose(renderMarkdown(codeFiles.joinToString("\n") { path -> - "* $path - ${codex.estimateTokenCount(root.resolve(path.toFile()).readText())} tokens" - })) - val toInput = { it: String -> listOf(codeSummary(), it) } - Retryable( - ui = ui, - task = task, - process = { content -> - val design = mainActor.answer(toInput(userMessage), api = api) - """ - |
- |${renderMarkdown(codeSummary())} - |
- | - |
${ - renderMarkdown( - ui.socketManager?.addApplyFileDiffLinks( - root = root.toPath(), - response = design, - handle = { newCodeMap -> - newCodeMap.forEach { (path, newCode) -> - content.append("$path Updated") - } - }, - ui = ui, - api = api, - )!! - ) - }
- """.trimMargin() - - }, - ) - } - } - - - private fun getFiles( - virtualFiles: Array?, - root: Path - ): MutableSet { - val codeFiles = mutableSetOf() - virtualFiles?.forEach { file -> - if (file.isDirectory) { - getFiles(file.children, root) - } else { - codeFiles.add(root.relativize(file.toNioPath())) - } - } - return codeFiles - } - - override fun isEnabled(event: AnActionEvent) = true - - companion object { - private val log = LoggerFactory.getLogger(MultiDiffChatAction::class.java) - - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiDiffChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiDiffChatAction.kt deleted file mode 100644 index f26467e3..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiDiffChatAction.kt +++ /dev/null @@ -1,230 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.MultiStepPatchAction.AutoDevApp.Settings -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.diff.addApplyFileDiffLinks -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.ChatClient -import com.simiacryptus.jopenai.models.ApiModel -import com.simiacryptus.jopenai.models.ApiModel.Role -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import com.simiacryptus.jopenai.util.GPT4Tokenizer -import com.simiacryptus.skyenet.Discussable -import com.simiacryptus.skyenet.core.actors.SimpleActor -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.core.util.getModuleRootForFile -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import org.slf4j.LoggerFactory -import java.io.File -import java.nio.file.Path -import java.util.UUID -import java.util.concurrent.Semaphore -import java.util.concurrent.atomic.AtomicReference - -class MultiDiffChatAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(event: AnActionEvent) { - val root: Path - - val dataContext = event.dataContext - val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) - val folder = UITools.getSelectedFolder(event) - root = if (null != folder) { - folder.toFile.toPath() - } else { - getModuleRootForFile(UITools.getSelectedFile(event)?.parent?.toFile ?: throw RuntimeException("")).toPath() - } - val initialFiles = getFiles(virtualFiles, root) - - val session = Session.newGlobalID() - SessionProxyServer.chats[session] = PatchApp(root.toFile(), initialFiles) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - val server = AppServer.getServer(event.project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - inner class PatchApp( - override val root: File, - private val initialFiles: Set, - ) : ApplicationServer( - applicationName = "Multi-file Patch Chat", - path = "/patchChat", - showMenubar = false, - ) { - override val singleInput = false - override val stickyInput = true - private fun getCodeFiles(): Set { - return initialFiles.filter { root.toPath().resolve(it).toFile().exists() }.toSet() - } - - private fun codeSummary(): String { - return getCodeFiles().associateWith { root.toPath().resolve(it).toFile().readText(Charsets.UTF_8) } - .entries.joinToString("\n\n") { (path, code) -> - val extension = - path.toString().split('.').lastOrNull()?.let { /*escapeHtml4*/(it)/*.indent(" ")*/ } - """ - # $path - ```$extension - ${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} - ``` - """.trimMargin() - } - } - - - override fun userMessage( - session: Session, - user: User?, - userMessage: String, - ui: ApplicationInterface, - api: API - ) { - fun mainActor() = SimpleActor( - prompt = """ - |You are a helpful AI that helps people with coding. - | - |You will be answering questions about the following code: - | - |${codeSummary()} - | - |Response should use one or more code patches in diff format within ```diff code blocks. - |Each diff should be preceded by a header that identifies the file being modified. - |The diff format should use + for line additions, - for line deletions. - |The diff should include 2 lines of context before and after every change. - | - |Example: - | - |Here are the patches: - | - |### src/utils/exampleUtils.js - |```diff - | // Utility functions for example feature - | const b = 2; - | function exampleFunction() { - |- return b + 1; - |+ return b + 2; - | } - |``` - | - |### tests/exampleUtils.test.js - |```diff - | // Unit tests for exampleUtils - | const assert = require('assert'); - | const { exampleFunction } = require('../src/utils/exampleUtils'); - | - | describe('exampleFunction', () => { - |- it('should return 3', () => { - |+ it('should return 4', () => { - | assert.equal(exampleFunction(), 3); - | }); - | }); - |``` - | - |If needed, new files can be created by using code blocks labeled with the filename in the same manner. - """.trimMargin(), - model = AppSettingsState.instance.smartModel.chatModel() - ) - - val settings = getSettings(session, user) ?: Settings() - if (api is ChatClient) api.budget = settings.budget ?: 2.00 - - val task = ui.newTask() - val api = (api as ChatClient).getChildClient().apply { - val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") - createFile.second?.apply { - logStreams += this.outputStream().buffered() - task.verbose("API log: $this") - } - } - val codex = GPT4Tokenizer() - task.verbose(renderMarkdown(getCodeFiles().joinToString("\n") { path -> - "* $path - ${codex.estimateTokenCount(root.resolve(path.toFile()).readText())} tokens" - })) - val toInput = { it: String -> listOf(codeSummary(), it) } - Discussable( - task = task, - userMessage = { userMessage }, - heading = renderMarkdown(userMessage), - initialResponse = { it: String -> mainActor().answer(toInput(it), api = api) }, - outputFn = { design: String -> - var markdown = ui.socketManager?.addApplyFileDiffLinks( - root = root.toPath(), - response = design, - handle = { newCodeMap -> - newCodeMap.forEach { (path, newCode) -> - task.complete("$path Updated") - } - }, - ui = ui, - api = api, - ) - """
${renderMarkdown(markdown!!)}
""" - }, - ui = ui, - reviseResponse = { userMessages: List> -> - mainActor().respond( - messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } - .toTypedArray()), - input = toInput(userMessage), - api = api - ) - }, - atomicRef = AtomicReference(), - semaphore = Semaphore(0), - ).call() - } - } - - - private fun getFiles( - virtualFiles: Array?, - root: Path - ): MutableSet { - val codeFiles = mutableSetOf() - virtualFiles?.forEach { file -> - if (file.isDirectory) { - getFiles(file.children, root) - } else { - codeFiles.add(root.relativize(file.toNioPath())) - } - } - return codeFiles - } - - override fun isEnabled(event: AnActionEvent) = true - - companion object { - private val log = LoggerFactory.getLogger(MultiDiffChatAction::class.java) - - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiStepPatchAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiStepPatchAction.kt deleted file mode 100644 index dff29145..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/MultiStepPatchAction.kt +++ /dev/null @@ -1,343 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import ai.grazie.utils.mpp.UUID -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.simiacryptus.diff.addApplyFileDiffLinks -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.ChatClient -import com.simiacryptus.jopenai.describe.Description -import com.simiacryptus.jopenai.models.ApiModel -import com.simiacryptus.jopenai.models.ApiModel.Role -import com.simiacryptus.jopenai.models.ChatModel -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ValidatedObject -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import com.simiacryptus.skyenet.AgentPatterns -import com.simiacryptus.skyenet.Discussable -import com.simiacryptus.skyenet.Retryable -import com.simiacryptus.skyenet.TabbedDisplay -import com.simiacryptus.skyenet.core.actors.* -import com.simiacryptus.skyenet.core.platform.* -import com.simiacryptus.skyenet.core.platform.file.DataStorage -import com.simiacryptus.skyenet.core.platform.model.StorageInterface -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.core.util.commonRoot -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.util.JsonUtil.toJson -import org.slf4j.LoggerFactory -import java.io.File -import java.nio.file.Path -import java.util.concurrent.Semaphore -import java.util.concurrent.atomic.AtomicReference - -class MultiStepPatchAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - val path = "/autodev" - - override fun handle(e: AnActionEvent) { - val session = Session.newGlobalID() - val storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) as DataStorage? - val selectedFile = UITools.getSelectedFolder(e) - if (null != storage && null != selectedFile) { - DataStorage.sessionPaths[session] = selectedFile.toFile - } - SessionProxyServer.chats[session] = AutoDevApp(event = e) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - open class AutoDevApp( - applicationName: String = "Auto Dev Assistant v1.2", - val temperature: Double = 0.1, - val event: AnActionEvent, - ) : ApplicationServer( - applicationName = applicationName, - path = "/autodev", - showMenubar = false, - ) { - override fun userMessage( - session: Session, - user: User?, - userMessage: String, - ui: ApplicationInterface, - api: API - ) { - val settings = getSettings(session, user) ?: Settings() - if (api is ChatClient) api.budget = settings.budget ?: 2.00 - AutoDevAgent( - api = api, - dataStorage = dataStorage, - session = session, - user = user, - ui = ui, - model = settings.model!!, - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - event = event, - ).start( - userMessage = userMessage, - ) - } - - data class Settings( - val budget: Double? = 2.00, - val tools: List = emptyList(), - val model: ChatModel? = AppSettingsState.instance.smartModel.chatModel(), - ) - - override val settingsClass: Class<*> get() = Settings::class.java - - @Suppress("UNCHECKED_CAST") - override fun initSettings(session: Session): T? = Settings() as T - } - - class AutoDevAgent( - val api: API, - dataStorage: StorageInterface, - session: Session, - user: User?, - val ui: ApplicationInterface, - val model: ChatModel, - val parsingModel: ChatModel, - actorMap: Map> = mapOf( - ActorTypes.DesignActor to ParsedActor( - resultClass = TaskList::class.java, - prompt = """ - Translate the user directive into an action plan for the project. - Break the user's request into a list of simple tasks to be performed. - For each task, provide a list of files to be modified and a description of the changes to be made. - """.trimIndent(), - model = model, - parsingModel = parsingModel, - ), - ActorTypes.TaskCodingActor to SimpleActor( - prompt = """ - |Implement the changes to the codebase as described in the task list. - | - |Response should use one or more code patches in diff format within ```diff code blocks. - |Each diff should be preceded by a header that identifies the file being modified. - |The diff format should use + for line additions, - for line deletions. - |The diff should include 2 lines of context before and after every change. - | - |Example: - | - |Here are the patches: - | - |### src/utils/exampleUtils.js - |```diff - | // Utility functions for example feature - | const b = 2; - | function exampleFunction() { - |- return b + 1; - |+ return b + 2; - | } - |``` - | - |### tests/exampleUtils.test.js - |```diff - | // Unit tests for exampleUtils - | const assert = require('assert'); - | const { exampleFunction } = require('../src/utils/exampleUtils'); - | - | describe('exampleFunction', () => { - |- it('should return 3', () => { - |+ it('should return 4', () => { - | assert.equal(exampleFunction(), 3); - | }); - | }); - |``` - """.trimMargin(), - model = model - ), - ), - val event: AnActionEvent, - ) : ActorSystem( - actorMap.map { it.key.name to it.value }.toMap(), dataStorage, user, session - ) { - enum class ActorTypes { - DesignActor, - TaskCodingActor, - } - - private val designActor by lazy { getActor(ActorTypes.DesignActor) as ParsedActor } - private val taskActor by lazy { getActor(ActorTypes.TaskCodingActor) as SimpleActor } - - fun start( - userMessage: String, - ) { - val codeFiles = mutableSetOf() - val root = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext) - ?.map { it.toFile.toPath() }?.toTypedArray()?.commonRoot()!! - PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(event.dataContext)?.forEach { file -> - // - codeFiles.add(root.relativize(file.toNioPath())) - } - require(codeFiles.isNotEmpty()) { "No files selected" } - fun codeSummary() = codeFiles.joinToString("\n\n") { path -> - "# $path\n```${ - path.toString().split('.').last() - }\n${root.resolve(path).toFile().readText()}\n```" - } - - val task = ui.newTask() - val api = (api as ChatClient).getChildClient().apply { - val createFile = task.createFile(".logs/api-${java.util.UUID.randomUUID()}.log") - createFile.second?.apply { - logStreams += this.outputStream().buffered() - task.verbose("API log: $this") - } - } - - val toInput = { it: String -> listOf(codeSummary(), it) } - val architectureResponse = Discussable( - task = task, - userMessage = { userMessage }, - heading = userMessage, - initialResponse = { it: String -> designActor.answer(toInput(it), api = api) }, - outputFn = { design: ParsedResponse -> - // renderMarkdown("${design.text}\n\n```json\n${JsonUtil.toJson(design.obj)/*.indent(" ")*/}\n```") - AgentPatterns.displayMapInTabs( - mapOf( - "Text" to renderMarkdown(design.text, ui = ui), - "JSON" to renderMarkdown("```json\n${toJson(design.obj)/*.indent(" ")*/}\n```", ui = ui), - ) - ) - }, - ui = ui, - reviseResponse = { userMessages: List> -> - designActor.respond( - messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } - .toTypedArray()), - input = toInput(userMessage), - api = api - ) - }, - atomicRef = AtomicReference(), - semaphore = Semaphore(0), - ).call() - - try { - val taskTabs = TabbedDisplay(task) - architectureResponse.obj.tasks.map { (paths, description) -> - var description = (description ?: UUID.random().toString()).trim() - // Strip `#` from the beginning of the description - while (description.startsWith("#")) { - description = description.substring(1) - } - description = renderMarkdown(description, ui = ui, tabs = false) - val task = ui.newTask(false).apply { taskTabs[description] = placeholder } - pool.submit { - task.header("Task: $description") - Retryable(ui, task) { - try { - val filter = codeFiles.filter { path -> - paths?.find { path.toString().contains(it) }?.isNotEmpty() == true - } - require(filter.isNotEmpty()) { - """ - |No files found for $paths - | - |Root: - |$root - | - |Files: - |${codeFiles.joinToString("\n")} - | - |Paths: - |${paths?.joinToString("\n") ?: ""} - | - """.trimMargin() - } - renderMarkdown(ui.socketManager!!.addApplyFileDiffLinks( - root = root, - response = taskActor.answer(listOf( - codeSummary(), - userMessage, - filter.joinToString("\n\n") { - "# ${it}\n```${ - it.toString().split('.').last().let { /*escapeHtml4*/it/*.indent(" ")*/ } - }\n${root.resolve(it).toFile().readText()}\n```" - }, - architectureResponse.text, - "Provide a change for ${paths?.joinToString(",") { it } ?: ""} ($description)" - ), api), - handle = { newCodeMap -> - newCodeMap.forEach { (path, newCode) -> - task.complete("$path Updated") - } - }, - ui = ui, - api = api - ) - ) - } catch (e: Exception) { - task.error(ui, e) - "" - } - } - } - }.toTypedArray().forEach { it.get() } - } catch (e: Exception) { - log.warn("Error", e) - } - } - } - - companion object { - private val log = LoggerFactory.getLogger(MultiStepPatchAction::class.java) - val root: File get() = File(AppSettingsState.instance.pluginHome, "code_chat") - - data class TaskList( - @Description("List of tasks to be performed in this project") - val tasks: List = emptyList() - ) : ValidatedObject { - override fun validate(): String? = when { - tasks.isEmpty() -> "Resources are required" - tasks.any { it.validate() != null } -> "Invalid resource" - else -> null - } - } - - data class Task( - @Description("List of paths involved in the task. This should include all files to be modified, and can include other files whose content will be informative in writing the changes.") - val paths: List? = null, - @Description("Detailed description of the changes to be made. Markdown format is supported.") - val description: String? = null - ) : ValidatedObject { - override fun validate(): String? = when { - paths.isNullOrEmpty() -> "Paths are required" - paths.any { it.isBlank() } -> "Invalid path" - else -> null - } - } - - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/SessionProxyApp.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/SessionProxyApp.kt deleted file mode 100644 index 75f1eb58..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/SessionProxyApp.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.chat.ChatServer -import com.simiacryptus.skyenet.webui.session.SocketManager - -class SessionProxyServer : ApplicationServer( - applicationName = "AI Coding Assistant", - path = "/", - showMenubar = false, -) { - override val singleInput = true - override val stickyInput = false - override fun appInfo(session: Session) = appInfoMap.getOrPut(session) { - AppInfoData( - applicationName = applicationName, - singleInput = singleInput, - stickyInput = stickyInput, - loadImages = false, - showMenubar = showMenubar - ) - }.toMap() - - override fun newSession(user: User?, session: Session) = - chats[session]?.newSession(user, session) ?: agents[session]!! - - companion object { - private val log = org.slf4j.LoggerFactory.getLogger(SessionProxyServer::class.java) - - val agents = mutableMapOf() - val chats = mutableMapOf() - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/ShellCommandAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/ShellCommandAction.kt deleted file mode 100644 index 7f4c1ee0..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/ShellCommandAction.kt +++ /dev/null @@ -1,143 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.ui.Messages -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.apps.code.CodingAgent -import com.simiacryptus.skyenet.core.actors.CodingActor -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.interpreter.ProcessInterpreter -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.session.SessionTask - -class ShellCommandAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent): Boolean { - return UITools.getSelectedFolder(event) != null - } - - override fun handle(e: AnActionEvent) { - val project = e.project - val selectedFolder = UITools.getSelectedFolder(e)?.toFile - if (selectedFolder == null) { - Messages.showErrorDialog(project, "Please select a directory", "Error") - return - } - val session = Session.newGlobalID() - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - SessionProxyServer.chats[session] = object : ApplicationServer( - applicationName = "Shell Agent", - path = "/shellAgent", - showMenubar = false, - ) { - override val singleInput = true - override val stickyInput = false - - - override fun userMessage( - session: Session, - user: User?, - userMessage: String, - ui: ApplicationInterface, - api: API - ) { - val task = ui.newTask() - val agent = object : CodingAgent( - api = api, - dataStorage = dataStorage, - session = session, - user = user, - ui = ui, - interpreter = ProcessInterpreter::class, - symbols = mapOf( - "workingDir" to selectedFolder.absolutePath, - "language" to if (isWindows) "powershell" else "bash", - "command" to listOf(AppSettingsState.instance.shellCommand) - ), - temperature = AppSettingsState.instance.temperature, - details = """ - Execute the following shell command(s) in the specified directory and provide the output. - Ensure to handle any errors or exceptions gracefully. - """.trimIndent(), - model = AppSettingsState.instance.smartModel.chatModel(), - mainTask = task, - ) { - override fun displayFeedback( - task: SessionTask, - request: CodingActor.CodeRequest, - response: CodingActor.CodeResult - ) { - val formText = StringBuilder() - var formHandle: StringBuilder? = null - formHandle = task.add( - """ - |
- |${ - if (!super.canPlay) "" else super.playButton( - task, - request, - response, - formText - ) { formHandle!! } - } - |${acceptButton(task, request, response, formText) { formHandle!! }} - |
- |${super.reviseMsg(task, request, response, formText) { formHandle!! }} - """.trimMargin(), className = "reply-message" - ) - formText.append(formHandle.toString()) - formHandle.toString() - task.complete() - } - - fun acceptButton( - task: SessionTask, - request: CodingActor.CodeRequest, - response: CodingActor.CodeResult, - formText: StringBuilder, - formHandle: () -> StringBuilder - ): String { - return ui.hrefLink("Accept", "href-link play-button") { - } - } - }.apply { - this.start(userMessage) - } - } - } - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - companion object { - private val isWindows = System.getProperty("os.name").lowercase().contains("windows") - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/SimpleCommandAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/SimpleCommandAction.kt deleted file mode 100644 index 4c7ce3a0..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/SimpleCommandAction.kt +++ /dev/null @@ -1,371 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.diff.FileValidationUtils -import com.simiacryptus.diff.FileValidationUtils.Companion.filteredWalk -import com.simiacryptus.diff.FileValidationUtils.Companion.isGitignore -import com.simiacryptus.diff.FileValidationUtils.Companion.isLLMIncludableFile -import com.simiacryptus.diff.addApplyFileDiffLinks -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.describe.Description -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.AgentPatterns -import com.simiacryptus.skyenet.Retryable -import com.simiacryptus.skyenet.core.actors.ParsedActor -import com.simiacryptus.skyenet.core.actors.SimpleActor -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.session.SessionTask -import com.simiacryptus.util.JsonUtil -import org.slf4j.LoggerFactory -import java.io.File -import java.nio.file.Files -import java.nio.file.Path -import kotlin.io.path.ExperimentalPathApi -import kotlin.io.path.walk - -class SimpleCommandAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(event: AnActionEvent) { - val settings = getUserSettings(event) ?: run { - log.error("Failed to retrieve user settings.") - return - } - val dataContext = event.dataContext - val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) - val folder = UITools.getSelectedFolder(event) - val root = folder?.toFile?.toPath() ?: event.project?.basePath?.let { File(it).toPath() } ?: run { - log.error("Failed to determine project root.") - return - } - - val session = Session.newGlobalID() - val patchApp = createPatchApp(root.toFile(), session, settings, virtualFiles) - SessionProxyServer.chats[session] = patchApp - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - val server = AppServer.getServer(event.project) - - openBrowserWithDelay(server.server.uri.resolve("/#$session")) - } - - private fun createPatchApp( - root: File, - session: Session, - settings: Settings, - virtualFiles: Array? - ): PatchApp { - return object : PatchApp(root, session, settings) { - override fun codeFiles() = (virtualFiles?.toList()?.flatMap { - FileValidationUtils.expandFileList(it.toFile).toList() - }?.map { it.toPath() }?.toSet()?.toMutableSet() ?: mutableSetOf()) - .filter { it.toFile().length() < 1024 * 1024 / 2 } // Limit to 0.5MB - .map { root.toPath().relativize(it) ?: it }.toSet() - - override fun codeSummary(paths: List) = paths - .filter { it.toFile().exists() } - .joinToString("\n\n") { path -> - """ - |# ${settings.workingDirectory.toPath()?.relativize(path)} - |$tripleTilde${path.toString().split('.').lastOrNull()} - |${path.toFile().readText(Charsets.UTF_8)} - |$tripleTilde - """.trimMargin() - } - - override fun projectSummary() = codeFiles() - .asSequence() - .filter { settings.workingDirectory.toPath()?.resolve(it)?.toFile()?.exists() == true } - .distinct().sorted() - .joinToString("\n") { path -> - "* ${path} - ${ - settings.workingDirectory.toPath()?.resolve(path)?.toFile()?.length() ?: "?" - } bytes".trim() - } - - override fun searchFiles(searchStrings: List): Set { - return searchStrings.flatMap { searchString -> - filteredWalk(settings.workingDirectory) { !isGitignore(it.toPath()) } - .filter { isLLMIncludableFile(it) } - .filter { it.readText().contains(searchString, ignoreCase = true) } - .map { it.toPath() } - .toList() - }.toSet() - } - } - } - - private fun openBrowserWithDelay(uri: java.net.URI) { - Thread { - Thread.sleep(500) - try { - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - abstract inner class PatchApp( - override val root: File, - val session: Session, - val settings: Settings, - ) : ApplicationServer( - applicationName = "Magic Code Genie", - path = "/doCmd", - showMenubar = false, - ) { - abstract fun codeFiles(): Set - abstract fun codeSummary(paths: List): String - abstract fun searchFiles(searchStrings: List): Set - override val singleInput = true - override val stickyInput = false - - override fun userMessage( - session: Session, - user: User?, - userMessage: String, - ui: ApplicationInterface, - api: API - ) { - val task = ui.newTask() - task.echo(renderMarkdown(userMessage)) - Thread { - run(ui, task, session, settings, userMessage) - }.start() - task.placeholder - } - - abstract fun projectSummary(): String - } - - private fun PatchApp.run( - ui: ApplicationInterface, - task: SessionTask, - session: Session, - settings: Settings, - userMessage: String = "" - ) { - try { - val planTxt = projectSummary() - task.add(renderMarkdown(planTxt)) - Retryable(ui, task) { - val plan = ParsedActor( - resultClass = ParsedTasks::class.java, - prompt = """ - |You are a helpful AI that helps people with coding. - | - |You will be answering questions about the following project: - | - |Project Root: ${settings.workingDirectory.absolutePath ?: ""} - | - |Files: - |$planTxt - | - |Given the request, identify one or more tasks. - |For each task: - | 1) predict the files that need to be fixed - | 2) predict related files that may be needed to debug the issue - """.trimMargin(), - model = AppSettingsState.instance.smartModel.chatModel() - ).answer( - listOf( - """ -Execute the following directive: - -$tripleTilde -$userMessage -$tripleTilde - """.trimMargin() - ), api = api - ) - val progressHeader = task.header("Processing tasks") - plan.obj.errors?.forEach { planTask -> - Retryable(ui, task) { - val paths = - ((planTask.fixFiles ?: emptyList()) + (planTask.relatedFiles ?: emptyList())).flatMap { - toPaths(settings.workingDirectory.toPath(), it) - } - val searchResults = searchFiles(planTask.searchStrings ?: emptyList()) - val combinedPaths = (paths + searchResults).distinct() - val prunedPaths = prunePaths(combinedPaths, 50 * 1024) - val codeSummary = - codeSummary(prunedPaths.map { settings.workingDirectory.toPath().resolve(it) }) - val response = SimpleActor( - prompt = """ - |You are a helpful AI that helps people with coding. - | - |You will be answering questions about the following code: - | - |$codeSummary - | - | - |Response should use one or more code patches in diff format within ${tripleTilde}diff code blocks. - |Each diff should be preceded by a header that identifies the file being modified. - |The diff format should use + for line additions, - for line deletions. - |The diff should include 2 lines of context before and after every change. - | - |Example: - | - |Here are the patches: - | - |### src/utils/exampleUtils.js - |${tripleTilde}diff - | // Utility functions for example feature - | const b = 2; - | function exampleFunction() { - |- return b + 1; - |+ return b + 2; - | } - |$tripleTilde - | - |### tests/exampleUtils.test.js - |${tripleTilde}diff - | // Unit tests for exampleUtils - | const assert = require('assert'); - | const { exampleFunction } = require('../src/utils/exampleUtils'); - | - | describe('exampleFunction', () => { - |- it('should return 3', () => { - |+ it('should return 4', () => { - | assert.equal(exampleFunction(), 3); - | }); - | }); - |$tripleTilde - | - |If needed, new files can be created by using code blocks labeled with the filename in the same manner. - """.trimMargin(), - model = AppSettingsState.instance.smartModel.chatModel() - ).answer( - listOf( - """ - |We are working on executing the following directive: - | - |${tripleTilde} - |$userMessage - |${tripleTilde} - | - |Focus on the task at hand: - | ${planTask.message?.replace("\n", "\n ") ?: ""} - |""".trimMargin() - ), api = api - ) - val markdown = ui.socketManager?.addApplyFileDiffLinks( - root = root.toPath(), - response = response, - handle = { newCodeMap -> - newCodeMap.forEach { (path, newCode) -> - task.complete("$path Updated") - } - }, - ui = ui, - api = api, - ) - "
${renderMarkdown(markdown!!)}
" - } - "" - } - progressHeader?.clear() - //task.append("", false) - AgentPatterns.displayMapInTabs( - mapOf( - "Text" to renderMarkdown(plan.text, ui = ui), - "JSON" to renderMarkdown( - "${tripleTilde}json\n${JsonUtil.toJson(plan.obj)}\n$tripleTilde", - ui = ui - ), - ) - ) - } - } catch (e: Exception) { - log.error("Error during task execution", e) - task.error(ui, e) - } - } - - private fun prunePaths(paths: List, maxSize: Int): List { - val sortedPaths = paths.sortedByDescending { it.toFile().length() } - var totalSize = 0 - val prunedPaths = mutableListOf() - for (path in sortedPaths) { - val fileSize = path.toFile().length().toInt() - if (totalSize + fileSize > maxSize) break - prunedPaths.add(path) - totalSize += fileSize - } - return prunedPaths - } - - data class ParsedTasks( - val errors: List? = null - ) - - data class ParsedTask( - @Description("The task to be performed") - val message: String? = null, - @Description("Files identified as needing modification and issue-related files, in order of descending relevance") - val relatedFiles: List? = null, - @Description("Files identified as needing modification and issue-related files, in order of descending relevance") - val fixFiles: List? = null, - @Description("Search strings to find relevant files, in order of descending relevance") - val searchStrings: List? = null - ) - - data class Settings( - var workingDirectory: File, - ) - - private fun getUserSettings(event: AnActionEvent?): Settings? { - val root = UITools.getSelectedFolder(event ?: return null)?.toNioPath() ?: event.project?.basePath?.let { - File(it).toPath() - } - val files = UITools.getSelectedFiles(event).map { it.path.let { File(it).toPath() } }.toMutableSet() - if (files.isEmpty()) Files.walk(root) - .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } - .toList().filterNotNull().forEach { files.add(it) } - return root?.toFile()?.let { Settings(it) } - } - - override fun isEnabled(event: AnActionEvent) = true - - companion object { - private val log = LoggerFactory.getLogger(SimpleCommandAction::class.java) - val tripleTilde = "`" + "``" // This is a workaround for the markdown parser when editing this file - - @OptIn(ExperimentalPathApi::class) - fun toPaths(root: Path, it: String): Iterable { - // Expand any wildcards - return if (it.contains("*")) { - val prefix = it.substringBefore("*") - val suffix = it.substringAfter("*") - val files = root.walk().toList() - files.filter { - it.toString().startsWith(prefix) && it.toString().endsWith(suffix) - } - } else { - listOf(Path.of(it)) - } - } - - } -} - diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/WebDevelopmentAssistantAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/WebDevelopmentAssistantAction.kt deleted file mode 100644 index 785394c3..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/generic/WebDevelopmentAssistantAction.kt +++ /dev/null @@ -1,651 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.generic - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.diff.addApplyFileDiffLinks -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.ChatClient -import com.simiacryptus.jopenai.describe.Description -import com.simiacryptus.jopenai.models.ApiModel -import com.simiacryptus.jopenai.models.ApiModel.Role -import com.simiacryptus.jopenai.models.ChatModel -import com.simiacryptus.jopenai.models.ImageModels -import com.simiacryptus.jopenai.models.OpenAIModels -import com.simiacryptus.jopenai.proxy.ValidatedObject -import com.simiacryptus.jopenai.util.ClientUtil.toContentList -import com.simiacryptus.skyenet.AgentPatterns -import com.simiacryptus.skyenet.Discussable -import com.simiacryptus.skyenet.TabbedDisplay -import com.simiacryptus.skyenet.core.actors.* -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.file.DataStorage -import com.simiacryptus.skyenet.core.platform.model.StorageInterface -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.session.SessionTask -import com.simiacryptus.util.JsonUtil -import org.slf4j.LoggerFactory -import java.io.ByteArrayOutputStream -import java.io.File -import java.nio.file.Path -import java.util.concurrent.Semaphore -import java.util.concurrent.atomic.AtomicReference -import javax.imageio.ImageIO -import kotlin.io.path.name - -val VirtualFile.toFile: File get() = File(this.path) - -class WebDevelopmentAssistantAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - val path = "/webDev" - - override fun handle(e: AnActionEvent) { - val session = Session.newGlobalID() - val selectedFile = UITools.getSelectedFolder(e) - if (null != selectedFile) { - DataStorage.sessionPaths[session] = selectedFile.toFile - } - SessionProxyServer.chats[session] = WebDevApp(root = selectedFile) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - override fun isEnabled(event: AnActionEvent): Boolean { - if (UITools.getSelectedFile(event)?.isDirectory == false) return false - return super.isEnabled(event) - } - - open class WebDevApp( - applicationName: String = "Web Development Agent", - val temperature: Double = 0.1, - root: VirtualFile?, - override val singleInput: Boolean = false, - ) : ApplicationServer( - applicationName = applicationName, - path = "/webdev", - showMenubar = false, - root = root?.toFile!!, - ) { - override fun userMessage( - session: Session, - user: User?, - userMessage: String, - ui: ApplicationInterface, - api: API - ) { - val settings = getSettings(session, user) ?: Settings() - if (api is ChatClient) api.budget = settings.budget ?: 2.00 - WebDevAgent( - api = api, - dataStorage = dataStorage, - session = session, - user = user, - ui = ui, - tools = settings.tools, - model = settings.model, - parsingModel = settings.parsingModel, - root = root, - ).start( - userMessage = userMessage, - ) - } - - data class Settings( - val budget: Double? = 2.00, - val tools: List = emptyList(), - val model: ChatModel = OpenAIModels.GPT4o, - val parsingModel: ChatModel = OpenAIModels.GPT4oMini, - ) - - override val settingsClass: Class<*> get() = Settings::class.java - - @Suppress("UNCHECKED_CAST") - override fun initSettings(session: Session): T? = Settings() as T - } - - class WebDevAgent( - val api: API, - dataStorage: StorageInterface, - session: Session, - user: User?, - val ui: ApplicationInterface, - val model: ChatModel, - val parsingModel: ChatModel, - val tools: List = emptyList(), - actorMap: Map> = mapOf( - ActorTypes.ArchitectureDiscussionActor to ParsedActor( - resultClass = ProjectSpec::class.java, - prompt = """ - Translate the user's idea into a detailed architecture for a simple web application. - - List all html, css, javascript, and image files to be created, and for each file: - 1. Mark with filename tags. - 2. Describe the public interface / interaction with other components. - 3. Core functional requirements. - - Specify user interactions and how the application will respond to them. - Identify key HTML classes and element IDs that will be used to bind the application to the HTML. - """.trimIndent(), - model = model, - parsingModel = parsingModel, - ), - ActorTypes.CodeReviewer to SimpleActor( - prompt = """ - |Analyze the code summarized in the user's header-labeled code blocks. - |Review, look for bugs, and provide fixes. - |Provide implementations for missing functions. - | - |Response should use one or more code patches in diff format within ```diff code blocks. - |Each diff should be preceded by a header that identifies the file being modified. - |The diff format should use + for line additions, - for line deletions. - |The diff should include 2 lines of context before and after every change. - | - |Example: - | - |Here are the patches: - | - |### src/utils/exampleUtils.js - |```diff - | // Utility functions for example feature - | const b = 2; - | function exampleFunction() { - |- return b + 1; - |+ return b + 2; - | } - |``` - | - |### tests/exampleUtils.test.js - |```diff - | // Unit tests for exampleUtils - | const assert = require('assert'); - | const { exampleFunction } = require('../src/utils/exampleUtils'); - | - | describe('exampleFunction', () => { - |- it('should return 3', () => { - |+ it('should return 4', () => { - | assert.equal(exampleFunction(), 3); - | }); - | }); - |``` - """.trimMargin(), - model = model, - ), - ActorTypes.HtmlCodingActor to SimpleActor( - prompt = """ - You will translate the user request into a skeleton HTML file for a rich javascript application. - The html file can reference needed CSS and JS files, which are will be located in the same directory as the html file. - Do not output the content of the resource files, only the html file. - """.trimIndent(), model = model - ), - ActorTypes.JavascriptCodingActor to SimpleActor( - prompt = """ - You will translate the user request into a javascript file for use in a rich javascript application. - """.trimIndent(), model = model - ), - ActorTypes.CssCodingActor to SimpleActor( - prompt = """ - You will translate the user request into a CSS file for use in a rich javascript application. - """.trimIndent(), model = model - ), - ActorTypes.EtcCodingActor to SimpleActor( - prompt = """ - You will translate the user request into a file for use in a web application. - """.trimIndent(), - model = model, - ), - ActorTypes.ImageActor to ImageActor( - prompt = """ - You will translate the user request into an image file for use in a web application. - """.trimIndent(), - textModel = model, - imageModel = ImageModels.DallE3, - ), - ), - val root: File, - ) : - ActorSystem( - actorMap.map { it.key.name to it.value }.toMap(), - dataStorage, - user, - session - ) { - enum class ActorTypes { - HtmlCodingActor, - JavascriptCodingActor, - CssCodingActor, - ArchitectureDiscussionActor, - CodeReviewer, - EtcCodingActor, - ImageActor, - } - - private val architectureDiscussionActor by lazy { getActor(ActorTypes.ArchitectureDiscussionActor) as ParsedActor } - private val htmlActor by lazy { getActor(ActorTypes.HtmlCodingActor) as SimpleActor } - private val imageActor by lazy { getActor(ActorTypes.ImageActor) as ImageActor } - private val javascriptActor by lazy { getActor(ActorTypes.JavascriptCodingActor) as SimpleActor } - private val cssActor by lazy { getActor(ActorTypes.CssCodingActor) as SimpleActor } - private val codeReviewer by lazy { getActor(ActorTypes.CodeReviewer) as SimpleActor } - private val etcActor by lazy { getActor(ActorTypes.EtcCodingActor) as SimpleActor } - - private val codeFiles = mutableSetOf() - - fun start( - userMessage: String, - ) { - val task = ui.newTask() - val toInput = { it: String -> listOf(it) } - val architectureResponse = Discussable( - task = task, - userMessage = { userMessage }, - initialResponse = { it: String -> architectureDiscussionActor.answer(toInput(it), api = api) }, - outputFn = { design: ParsedResponse -> - // renderMarkdown("${design.text}\n\n```json\n${JsonUtil.toJson(design.obj)/*.indent(" ")*/}\n```") - AgentPatterns.displayMapInTabs( - mapOf( - "Text" to renderMarkdown(design.text, ui = ui), - "JSON" to renderMarkdown( - "```json\n${JsonUtil.toJson(design.obj)/*.indent(" ")*/}\n```", - ui = ui - ), - ) - ) - }, - ui = ui, - reviseResponse = { userMessages: List> -> - architectureDiscussionActor.respond( - messages = (userMessages.map { ApiModel.ChatMessage(it.second, it.first.toContentList()) } - .toTypedArray()), - input = toInput(userMessage), - api = api - ) - }, - atomicRef = AtomicReference(), - semaphore = Semaphore(0), - heading = userMessage - ).call() - - - try { -// val toolSpecs = tools.map { ToolServlet.tools.find { t -> t.path == it } } -// .joinToString("\n\n") { it?.let { JsonUtil.toJson(it.openApiDescription) } ?: "" } - var messageWithTools = userMessage -// if (toolSpecs.isNotBlank()) messageWithTools += "\n\nThese services are available:\n$toolSpecs" - task.echo( - renderMarkdown( - "```json\n${JsonUtil.toJson(architectureResponse.obj)/*.indent(" ")*/}\n```", - ui = ui - ) - ) - val fileTabs = TabbedDisplay(task) - architectureResponse.obj.files.filter { - !it.name!!.startsWith("http") - }.map { (path, description) -> - val task = ui.newTask(false).apply { fileTabs[path.toString()] = placeholder } - task.header("Drafting $path") - codeFiles.add(File(path).toPath()) - pool.submit { - when (path!!.split(".").last().lowercase()) { - - "js" -> draftResourceCode( - task = task, - request = javascriptActor.chatMessages( - listOf( - messageWithTools, - architectureResponse.text, - "Render $path - $description" - ) - ), - actor = javascriptActor, - path = File(path).toPath(), "js", "javascript" - ) - - - "css" -> draftResourceCode( - task = task, - request = cssActor.chatMessages( - listOf( - messageWithTools, - architectureResponse.text, - "Render $path - $description" - ) - ), - actor = cssActor, - path = File(path).toPath() - ) - - "html" -> draftResourceCode( - task = task, - request = htmlActor.chatMessages( - listOf( - messageWithTools, - architectureResponse.text, - "Render $path - $description" - ) - ), - actor = htmlActor, - path = File(path).toPath() - ) - - "png" -> draftImage( - task = task, - request = etcActor.chatMessages( - listOf( - messageWithTools, - architectureResponse.text, - "Render $path - $description" - ) - ), - actor = imageActor, - path = File(path).toPath() - ) - - "jpg" -> draftImage( - task = task, - request = etcActor.chatMessages( - listOf( - messageWithTools, - architectureResponse.text, - "Render $path - $description" - ) - ), - actor = imageActor, - path = File(path).toPath() - ) - - else -> draftResourceCode( - task = task, - request = etcActor.chatMessages( - listOf( - messageWithTools, - architectureResponse.text, - "Render $path - $description" - ) - ), - actor = etcActor, - path = File(path).toPath() - ) - - } - } - }.toTypedArray().forEach { it.get() } - // Apply codeReviewer - - iterateCode(task) - } catch (e: Throwable) { - log.warn("Error", e) - task.error(ui, e) - } - } - - fun codeSummary() = codeFiles.filter { - if (it.name.lowercase().endsWith(".png")) return@filter false - if (it.name.lowercase().endsWith(".jpg")) return@filter false - true - }.joinToString("\n\n") { path -> - "# $path\n```${path.toString().split('.').last()}\n${root.resolve(path.toFile()).readText()}\n```" - } - - private fun iterateCode( - task: SessionTask - ) { - Discussable( - task = task, - heading = "Code Refinement", - userMessage = { codeSummary() }, - initialResponse = { - codeReviewer.answer(listOf(it), api = api) - }, - outputFn = { code -> - renderMarkdown( - ui.socketManager!!.addApplyFileDiffLinks( - root = root.toPath(), - response = code, - handle = { newCodeMap -> - newCodeMap.forEach { (path, newCode) -> - task.complete("$path Updated") - } - }, - ui = ui, - api = api - ) - ) - }, - ui = ui, - reviseResponse = { userMessages -> - val userMessages = userMessages.toMutableList() - userMessages.set(0, userMessages.get(0).copy(first = codeSummary())) - val combinedMessages = - userMessages.map { ApiModel.ChatMessage(Role.user, it.first.toContentList()) } - codeReviewer.respond( - input = listOf(element = combinedMessages.joinToString("\n")), - api = api, - messages = combinedMessages.toTypedArray(), - ) - }, - ).call() - } - - private fun draftImage( - task: SessionTask, - request: Array, - actor: ImageActor, - path: Path, - ) { - try { - var code = Discussable( - task = task, - userMessage = { "" }, - heading = "Drafting $path", - initialResponse = { - val messages = (request + ApiModel.ChatMessage(Role.user, "Draft $path".toContentList())) - .toList().toTypedArray() - actor.respond( - listOf(request.joinToString("\n") { it.content?.joinToString() ?: "" }), - api, - *messages - ) - - }, - outputFn = { img -> - renderMarkdown( - "", ui = ui - ) - }, - ui = ui, - reviseResponse = { userMessages: List> -> - actor.respond( - messages = (request.toList() + userMessages.map { - ApiModel.ChatMessage( - it.second, - it.first.toContentList() - ) - }) - .toTypedArray(), - input = listOf(element = (request.toList() + userMessages.map { - ApiModel.ChatMessage( - it.second, - it.first.toContentList() - ) - }) - .joinToString("\n") { it.content?.joinToString() ?: "" }), - api = api, - ) - }, - ).call() - task.complete( - renderMarkdown( - "", ui = ui - ) - ) - } catch (e: Throwable) { - val error = task.error(ui, e) - task.complete(ui.hrefLink("♻", "href-link regen-button") { - error?.clear() - draftImage(task, request, actor, path) - }) - } - } - - private fun write( - code: ImageResponse, - path: Path - ): ByteArray { - val byteArrayOutputStream = ByteArrayOutputStream() - ImageIO.write( - code.image, - path.toString().split(".").last(), - byteArrayOutputStream - ) - val bytes = byteArrayOutputStream.toByteArray() - return bytes - } - - private fun draftResourceCode( - task: SessionTask, - request: Array, - actor: SimpleActor, - path: Path, - vararg languages: String = arrayOf(path.toString().split(".").last().lowercase()), - ) { - try { - var code = Discussable( - task = task, - userMessage = { "Drafting $path" }, - heading = "", - initialResponse = { - actor.respond( - listOf(request.joinToString("\n") { it.content?.joinToString() ?: "" }), - api, - *(request + ApiModel.ChatMessage(Role.user, "Draft $path".toContentList())) - .toList().toTypedArray() - ) - }, - outputFn = { design: String -> - var design = design - languages.forEach { language -> - if (design.contains("```$language")) { - design = design.substringAfter("```$language").substringBefore("```") - } - } - renderMarkdown("```${languages.first()}\n${design.let { it }}\n```", ui = ui) - }, - ui = ui, - reviseResponse = { userMessages: List> -> - actor.respond( - messages = (request.toList() + userMessages.map { - ApiModel.ChatMessage( - it.second, - it.first.toContentList() - ) - }) - .toTypedArray(), - input = listOf(element = (request.toList() + userMessages.map { - ApiModel.ChatMessage( - it.second, - it.first.toContentList() - ) - }) - .joinToString("\n") { it.content?.joinToString() ?: "" }), - api = api, - ) - }, - ).call() - code = extractCode(code) - task.complete( - "$path Updated" - ) - } catch (e: Throwable) { - val error = task.error(ui, e) - task.complete(ui.hrefLink("♻", "href-link regen-button") { - error?.clear() - draftResourceCode(task, request, actor, path, *languages) - }) - } - } - - private fun extractCode(code: String): String { - var code = code - code = code.trim() - "(?s)```[^\\n]*\n(.*)\n```".toRegex().find(code)?.let { - code = it.groupValues[1] - } - return code - } - - } - - companion object { - private val log = LoggerFactory.getLogger(WebDevelopmentAssistantAction::class.java) - val root: File get() = File(AppSettingsState.instance.pluginHome, "code_chat") - - data class ProjectSpec( - @Description("Files in the project design, including all local html, css, and js files.") - val files: List = emptyList() - ) : ValidatedObject { - override fun validate(): String? = when { - files.isEmpty() -> "Resources are required" - files.any { it.validate() != null } -> "Invalid resource" - else -> null - } - } - - data class ProjectFile( - @Description("The path to the file, relative to the project root.") - val name: String? = "", - @Description("A brief description of the file's purpose and contents.") - val description: String? = "" - ) : ValidatedObject { - override fun validate(): String? = when { - name.isNullOrBlank() -> "Path is required" - name.contains(" ") -> "Path cannot contain spaces" - !name.contains(".") -> "Path must contain a file extension" - else -> null - } - } - - } - -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ChatWithCommitAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ChatWithCommitAction.kt deleted file mode 100644 index 9a9804b0..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ChatWithCommitAction.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.git - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.CodeChatSocketManager -import com.github.simiacryptus.aicoder.util.IdeaChatClient -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.vcs.VcsDataKeys -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.diff.IterativePatchUtil -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import java.io.File - -val String.isBinary: Boolean - get() { - val binary = this.toByteArray().filter { it < 0x20 || it > 0x7E } - return binary.size > this.length / 10 - } - -class ChatWithCommitAction : AnAction() { - private val logger = Logger.getInstance(ChatWithCommitAction::class.java) - - override fun actionPerformed(e: AnActionEvent) { - logger.info("Comparing selected revision with the current working copy") - val files = expand(e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)) - val changes = e.getData(VcsDataKeys.CHANGES) - Thread { - try { - val map = changes?.toList() - ?.associateBy { (it.beforeRevision?.file ?: it.afterRevision?.file)!!.toString() } - val msg = map?.entries - ?.filter { (file, change) -> - val find = files?.find { it.toNioPath().toFile().absolutePath == File(file).absolutePath } - find != null - } - ?.joinToString("\n\n") { (file, change) -> - val before = change.beforeRevision?.content - val after = change.afterRevision?.content - if ((before ?: after)!!.isBinary) - return@joinToString "# Binary: ${change.afterRevision?.file}".replace("\n", "\n ") - if (before == null) return@joinToString "# Deleted: ${change.afterRevision?.file}\n${after}".replace( - "\n", - "\n " - ) - if (after == null) return@joinToString "# Added: ${change.beforeRevision?.file}\n${before}".replace( - "\n", - "\n " - ) - val diff = IterativePatchUtil.generatePatch(before, after) - "# Change: ${change.beforeRevision?.file}\n$diff".replace("\n", "\n ") - } - - // Open chat with the diff information - openChatWithDiff(e, msg ?: "No changes found") - } catch (e: Throwable) { - logger.error("Error comparing changes", e) - } - }.start() - } - - private fun openChatWithDiff(e: AnActionEvent, diffInfo: String) { - val session = Session.newGlobalID() - SessionProxyServer.agents[session] = CodeChatSocketManager( - session = session, - language = "diff", - codeSelection = diffInfo, - filename = "commit_changes.diff", - api = IdeaChatClient.instance, - model = AppSettingsState.instance.smartModel.chatModel(), - storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) - ) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - logger.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - logger.warn("Error opening browser", e) - } - }.start() - } - - private fun expand(data: Array?): Array? { - return data?.flatMap { - if (it.isDirectory) { - expand(it.children.toList().toTypedArray())?.toList() ?: listOf() - } else { - listOf(it) - } - }?.toTypedArray() - } - - override fun update(e: AnActionEvent) { - e.presentation.isEnabledAndVisible = e.getData(PlatformDataKeys.PROJECT) != null && - e.getData(VcsDataKeys.VCS)?.name != "Git" - } - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ChatWithCommitDiffAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ChatWithCommitDiffAction.kt deleted file mode 100644 index b30ecf74..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ChatWithCommitDiffAction.kt +++ /dev/null @@ -1,146 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.git - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.CodeChatSocketManager -import com.github.simiacryptus.aicoder.util.IdeaChatClient -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.project.Project -import com.intellij.openapi.vcs.LocalFilePath -import com.intellij.openapi.vcs.ProjectLevelVcsManager -import com.intellij.openapi.vcs.VcsDataKeys -import com.intellij.openapi.vcs.changes.Change -import com.intellij.openapi.vcs.changes.ChangeListManager -import com.intellij.openapi.vcs.changes.CurrentContentRevision -import com.intellij.openapi.vcs.changes.TextRevisionNumber -import com.intellij.openapi.vcs.history.VcsRevisionNumber -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import javax.swing.JOptionPane - -class ChatWithCommitDiffAction : AnAction() { - companion object { - private val log = Logger.getInstance(ChatWithCommitDiffAction::class.java) - } - - override fun actionPerformed(e: AnActionEvent) { - log.info("Comparing selected commit with the current HEAD") - val project = e.project ?: return - val selectedCommit = e.getData(VcsDataKeys.VCS_REVISION_NUMBER) ?: return - val vcsManager = ProjectLevelVcsManager.getInstance(project) - val vcs = vcsManager.allActiveVcss.firstOrNull() ?: run { - JOptionPane.showMessageDialog(null, "No active VCS found", "Error", JOptionPane.ERROR_MESSAGE) - return - } - - Thread { - try { - val diffInfo = getChangesBetweenCommits(project, selectedCommit).ifEmpty { "No changes found" } - openChatWithDiff(e, diffInfo) - } catch (e: Throwable) { - log.error("Error comparing changes", e) - JOptionPane.showMessageDialog(null, e.message, "Error", JOptionPane.ERROR_MESSAGE) - } - }.start() - } - - private fun openChatWithDiff(e: AnActionEvent, diffInfo: String) { - val session = Session.newGlobalID() - SessionProxyServer.agents[session] = CodeChatSocketManager( - session = session, - language = "diff", - codeSelection = diffInfo, - filename = "commit_changes.diff", - api = IdeaChatClient.instance, - model = AppSettingsState.instance.smartModel.chatModel(), - storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) - ) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - private fun getChangesBetweenCommits(project: Project, selectedCommit: VcsRevisionNumber): String { - val commitID = (selectedCommit as TextRevisionNumber).asString() - val changeListManager = ChangeListManager.getInstance(project) - val changes = changeListManager.allChanges - return changes.joinToString("\n") { change: Change -> - buildString { - appendLine("File: ${change.virtualFile?.path ?: "Unknown"}") - appendLine("Type: ${change.type}") - appendLine(getDiffForChange(project, change, selectedCommit) ?: "No diff available") - } - } - } - - private fun getDiffForChange(project: Project, change: Change, selectedCommit: VcsRevisionNumber): String? { - val file = change.virtualFile ?: return null - val currentContent = change.afterRevision?.content ?: return null - val selectedContent = getContentForRevision(project, file, selectedCommit) ?: return null - return createSimpleDiff(currentContent, selectedContent) - } - - private fun getContentForRevision(project: Project, file: VirtualFile, revisionNumber: VcsRevisionNumber): String? { - try { - val contentRevision = CurrentContentRevision(LocalFilePath(file.path, file.isDirectory)) - return contentRevision.content - } catch (e: Exception) { - log.error("Error getting content for revision", e) - return null - } - } - - private fun createSimpleDiff(currentContent: String, selectedContent: String): String { - val currentLines = currentContent.lines() - val selectedLines = selectedContent.lines() - val diff = StringBuilder() - for ((index, line) in currentLines.withIndex()) { - if (index >= selectedLines.size) { - diff.appendLine("+ $line") - } else if (line != selectedLines[index]) { - diff.appendLine("- ${selectedLines[index]}") - diff.appendLine("+ $line") - } - } - if (selectedLines.size > currentLines.size) { - for (i in currentLines.size until selectedLines.size) { - diff.appendLine("- ${selectedLines[i]}") - } - } - return diff.toString() - } - - - override fun update(e: AnActionEvent) { - val project = e.project - e.presentation.isEnabledAndVisible = project != null && - ProjectLevelVcsManager.getInstance(project).allActiveVcss.isNotEmpty() - } - -} - diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ChatWithWorkingCopyDiffAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ChatWithWorkingCopyDiffAction.kt deleted file mode 100644 index 92f0b112..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ChatWithWorkingCopyDiffAction.kt +++ /dev/null @@ -1,129 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.git - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.CodeChatSocketManager -import com.github.simiacryptus.aicoder.util.IdeaChatClient -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.vcs.VcsDataKeys -import com.intellij.openapi.vcs.changes.ChangeListManager -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import javax.swing.JOptionPane - -class ChatWithWorkingCopyDiffAction : AnAction() { - companion object { - private val log = Logger.getInstance(ChatWithWorkingCopyDiffAction::class.java) - } - - override fun actionPerformed(e: AnActionEvent) { - log.info("Comparing HEAD with the working copy") - val project = e.project ?: return - val files = e.getData(VcsDataKeys.VIRTUAL_FILES)?.firstOrNull() - val changeListManager = ChangeListManager.getInstance(project) - - Thread { - try { - val diffInfo = getWorkingCopyDiff(changeListManager) - openChatWithDiff(e, diffInfo) - } catch (e: Throwable) { - log.error("Error comparing changes", e) - JOptionPane.showMessageDialog(null, e.message, "Error", JOptionPane.ERROR_MESSAGE) - } - }.start() - } - - private fun openChatWithDiff(e: AnActionEvent, diffInfo: String) { - val session = Session.newGlobalID() - SessionProxyServer.agents[session] = CodeChatSocketManager( - session = session, - language = "diff", - codeSelection = diffInfo, - filename = "working_copy_changes.diff", - api = IdeaChatClient.instance, - model = AppSettingsState.instance.smartModel.chatModel(), - storage = ApplicationServices.dataStorageFactory(AppSettingsState.instance.pluginHome) - ) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - - private fun getWorkingCopyDiff(changeListManager: ChangeListManager): String { - val changes = changeListManager.allChanges - return changes.joinToString("\n\n") { change -> - val diffForChange = getDiffForChange(change) - "File: ${change.virtualFile?.path ?: "Unknown"}\n" + - "Type: ${change.type}\n" + - (diffForChange ?: "No diff available") - }.ifEmpty { "No changes found" } - } - - private fun getDiffForChange(change: com.intellij.openapi.vcs.changes.Change): String? { - val beforeRevision = change.beforeRevision - val afterRevision = change.afterRevision - - if (beforeRevision == null && afterRevision == null) { - return null - } - - val beforeContent = beforeRevision?.content ?: "" - val afterContent = afterRevision?.content ?: "" - - return createSimpleDiff(beforeContent, afterContent) - } - - private fun createSimpleDiff(beforeContent: String, afterContent: String): String { - val beforeLines = beforeContent.lines() - val afterLines = afterContent.lines() - val diff = StringBuilder() - - for ((index, line) in afterLines.withIndex()) { - if (index >= beforeLines.size) { - diff.appendLine("+ $line") - } else if (line != beforeLines[index]) { - diff.appendLine("- ${beforeLines[index]}") - diff.appendLine("+ $line") - } - } - - if (beforeLines.size > afterLines.size) { - for (i in afterLines.size until beforeLines.size) { - diff.appendLine("- ${beforeLines[i]}") - } - } - - return diff.toString() - } - - override fun update(e: AnActionEvent) { - val project = e.project ?: return - val vcs = e.getData(VcsDataKeys.VCS) - e.presentation.isEnabledAndVisible = project != null && vcs != null - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ReplicateCommitAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ReplicateCommitAction.kt deleted file mode 100644 index 5e5bef12..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/git/ReplicateCommitAction.kt +++ /dev/null @@ -1,406 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.git - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.actions.generic.toFile -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.vcs.VcsDataKeys -import com.intellij.openapi.vcs.changes.Change -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.diff.FileValidationUtils -import com.simiacryptus.diff.IterativePatchUtil -import com.simiacryptus.diff.addApplyFileDiffLinks -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.describe.Description -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.AgentPatterns -import com.simiacryptus.skyenet.Retryable -import com.simiacryptus.skyenet.core.actors.ParsedActor -import com.simiacryptus.skyenet.core.actors.SimpleActor -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.session.SessionTask -import com.simiacryptus.util.JsonUtil -import org.slf4j.LoggerFactory -import java.io.File -import java.nio.file.Files -import java.nio.file.Path -import kotlin.io.path.ExperimentalPathApi -import kotlin.io.path.walk - -class ReplicateCommitAction : BaseAction() { - private val logger = Logger.getInstance(ReplicateCommitAction::class.java) - - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(event: AnActionEvent) { - val settings = getUserSettings(event) ?: return - val dataContext = event.dataContext - val virtualFiles = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) - val folder = UITools.getSelectedFolder(event) - var root = if (null != folder) { - folder.toFile.toPath() - } else { - event.project?.basePath?.let { File(it).toPath() } - }!! - - val virtualFiles1 = event.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) - val files = expand(virtualFiles1) - val changes = event.getData(VcsDataKeys.CHANGES) - val session = Session.newGlobalID() - - Thread { - try { - val diffInfo = generateDiffInfo(files, changes) - val patchApp = object : PatchApp(root.toFile(), session, settings, diffInfo) { - override fun codeFiles() = getFiles(virtualFiles) - .filter { it.toFile().length() < 1024 * 1024 / 2 } // Limit to 0.5MB - .map { root.relativize(it) ?: it }.toSet() - - override fun codeSummary(paths: List): String = paths - .filter { it.toFile().exists() } - .joinToString("\n\n") { path -> - """ - |# ${settings.workingDirectory.toPath()?.relativize(path)} - |$tripleTilde${path.toString().split('.').lastOrNull()} - |${path.toFile().readText(Charsets.UTF_8)} - |$tripleTilde - """.trimMargin() - } - - override fun projectSummary(): String { - val codeFiles = codeFiles() - val str = codeFiles - .asSequence() - .filter { settings.workingDirectory.toPath()?.resolve(it)?.toFile()?.exists() == true } - .distinct().sorted() - .joinToString("\n") { path -> - "* ${path} - ${ - settings.workingDirectory.toPath()?.resolve(path)?.toFile()?.length() ?: "?" - } bytes".trim() - } - return str - } - } - SessionProxyServer.chats[session] = patchApp - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - Thread { - Thread.sleep(500) - try { - val server = AppServer.getServer(event.project) - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - private fun generateDiffInfo(files: Array?, changes: Array?): String { - val map = changes?.toList() - ?.associateBy { (it.beforeRevision?.file ?: it.afterRevision?.file)!!.toString() } - val entries = map?.entries - ?.filter { (file, change) -> - try { - val find = files?.find { it.toNioPath().toFile().absolutePath == File(file).absolutePath } - find != null - } catch (e: Exception) { - logger.error("Error comparing changes", e) - false - } - } - return entries - ?.joinToString("\n\n") { (file, change) -> - val before = change.beforeRevision?.content - val after = change.afterRevision?.content - if ((before ?: after)!!.isBinary) - return@joinToString "# Binary: ${change.afterRevision?.file}".replace("\n", "\n ") - if (before == null) return@joinToString "# Deleted: ${change.afterRevision?.file}\n${after}".replace( - "\n", - "\n " - ) - if (after == null) return@joinToString "# Added: ${change.beforeRevision?.file}\n${before}".replace( - "\n", - "\n " - ) - val diff = IterativePatchUtil.generatePatch(before, after) - "# Change: ${change.beforeRevision?.file}\n$diff".replace("\n", "\n ") - } ?: "No changes found" - } - - abstract inner class PatchApp( - override val root: File, - val session: Session, - val settings: Settings, - val diffInfo: String, - ) : ApplicationServer( - applicationName = "Replicate Commit", - path = "/replicateCommit", - showMenubar = false, - ) { - abstract fun codeFiles(): Set - abstract fun codeSummary(paths: List): String - override val singleInput = true - override val stickyInput = false - - override fun userMessage( - session: Session, - user: User?, - userMessage: String, - ui: ApplicationInterface, - api: API - ) { - val task = ui.newTask() - task.echo(userMessage) - Thread { - run(ui, task, session, settings, userMessage, diffInfo) - }.start() - task.placeholder - } - - abstract fun projectSummary(): String - } - - private fun PatchApp.run( - ui: ApplicationInterface, - task: SessionTask, - session: Session, - settings: Settings, - userMessage: String = "", - diffInfo: String - ) { - try { - val planTxt = projectSummary() - task.add(renderMarkdown(planTxt)) - Retryable(ui, task) { - val plan = ParsedActor( - resultClass = ParsedTasks::class.java, - prompt = """ - |You are a helpful AI that helps people with coding. - - |You will be answering questions about the following project: - - |Project Root: ${settings.workingDirectory.absolutePath ?: ""} - - |Files: - |$planTxt - - |Given the request, identify one or more tasks. - |For each task: - | 1) predict the files that need to be fixed - | 2) predict related files that may be needed to debug the issue - """.trimMargin(), - model = AppSettingsState.instance.smartModel.chatModel() - ).answer( - listOf( - """ - |We want to create a change based on the following prior commit: - - |$tripleTilde - |$diffInfo - |$tripleTilde - | - |The change should implement the user's request: - - |$tripleTilde - |$userMessage - |$tripleTilde - """.trimMargin() - ), api = api - ) - task.add( - AgentPatterns.displayMapInTabs( - mapOf( - "Text" to renderMarkdown(plan.text, ui = ui), - "JSON" to renderMarkdown( - "${tripleTilde}json\n${JsonUtil.toJson(plan.obj)}\n$tripleTilde", - ui = ui - ), - ) - ) - ) - plan.obj.errors?.map { planTask -> - Retryable(ui, task) { - val paths = - ((planTask.fixFiles ?: emptyList()) + (planTask.relatedFiles ?: emptyList())).flatMap { - toPaths(settings.workingDirectory.toPath(), it) - } - val codeSummary = codeSummary(paths) - val response = SimpleActor( - prompt = """ - |You are a helpful AI that helps people with coding. - - |You will be answering questions about the following code: - - |$codeSummary - - - |Response should use one or more code patches in diff format within ${tripleTilde}diff code blocks. - |Each diff should be preceded by a header that identifies the file being modified. - |The diff format should use + for line additions, - for line deletions. - |The diff should include 2 lines of context before and after every change. - - |Example: - - |Here are the patches: - - |### src/utils/exampleUtils.js - |${tripleTilde}diff - | // Utility functions for example feature - | const b = 2; - | function exampleFunction() { - |- return b + 1; - |+ return b + 2; - | } - |$tripleTilde - - |### tests/exampleUtils.test.js - |${tripleTilde}diff - | // Unit tests for exampleUtils - | const assert = require('assert'); - | const { exampleFunction } = require('../src/utils/exampleUtils'); - | - | describe('exampleFunction', () => { - |- it('should return 3', () => { - |+ it('should return 4', () => { - | assert.equal(exampleFunction(), 3); - | }); - | }); - |$tripleTilde - - |If needed, new files can be created by using code blocks labeled with the filename in the same manner. - """.trimMargin(), - model = AppSettingsState.instance.smartModel.chatModel() - ).answer( - listOf( - """ - |We are working on executing the following directive: - - |${tripleTilde} - |$userMessage - |${tripleTilde} - - |Focus on the task at hand: - | ${planTask.message?.replace("\n", "\n ") ?: ""} - """.trimMargin() - ), api = api - ) - var markdown = ui.socketManager?.addApplyFileDiffLinks( - root = root.toPath(), - response = response, - handle = { newCodeMap -> - newCodeMap.forEach { (path, newCode) -> - task.complete("$path Updated") - } - }, - ui = ui, - api = api, - ) - "
${renderMarkdown(markdown!!)}
" - } - "" - }?.joinToString { it } ?: "" - } - } catch (e: Exception) { - task.error(ui, e) - } - } - - data class ParsedTasks( - val errors: List? = null - ) - - data class ParsedTask( - @Description("The task to be performed") - val message: String? = null, - @Description("Files identified as needing modification and issue-related files") - val relatedFiles: List? = null, - @Description("Files identified as needing modification and issue-related files") - val fixFiles: List? = null - ) - - data class Settings( - var workingDirectory: File, - ) - - private fun getFiles( - virtualFiles: Array? - ): MutableSet { - val codeFiles = mutableSetOf() // Set to avoid duplicates - virtualFiles?.forEach { file -> - if (file.isDirectory) { - if (file.name.startsWith(".")) return@forEach - if (FileValidationUtils.Companion.isGitignore(file.toNioPath())) return@forEach - codeFiles.addAll(getFiles(file.children)) - } else { - codeFiles.add((file.toNioPath())) - } - } - return codeFiles - } - - private fun getUserSettings(event: AnActionEvent?): Settings? { - val root = UITools.getSelectedFolder(event ?: return null)?.toNioPath() ?: event.project?.basePath?.let { File(it).toPath() } - val files = UITools.getSelectedFiles(event).map { it.path.let { File(it).toPath() } }.toMutableSet() - if (files.isEmpty()) Files.walk(root) - .filter { Files.isRegularFile(it) && !Files.isDirectory(it) } - .toList().filterNotNull().forEach { files.add(it) } - return Settings(root?.toFile() ?: return null) - } - - private fun expand(data: Array?): Array? { - return data?.flatMap { - if (it.isDirectory) { - expand(it.children.toList().toTypedArray())?.toList() ?: listOf() - } else { - listOf(it) - } - }?.toTypedArray() - } - - override fun isEnabled(event: AnActionEvent) = true - - companion object { - private val log = LoggerFactory.getLogger(ReplicateCommitAction::class.java) - val tripleTilde = "`" + "``" // This is a workaround for the markdown parser when editing this file - - @OptIn(ExperimentalPathApi::class) - fun toPaths(root: Path, it: String): Iterable { - // Expand any wildcards - if (it.contains("*")) { - val prefix = it.substringBefore("*") - val suffix = it.substringAfter("*") - val files = root.walk().toList() - val pathList = files.filter { - it.toString().startsWith(prefix) && it.toString().endsWith(suffix) - }.toList() - return pathList - } else { - return listOf(Path.of(it)) - } - } - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/CreateProjectorFromQueryIndexAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/CreateProjectorFromQueryIndexAction.kt deleted file mode 100644 index 97089ab2..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/CreateProjectorFromQueryIndexAction.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.knowledge - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.github.simiacryptus.aicoder.util.findRecursively -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.progress.ProgressManager -import com.intellij.openapi.progress.Task -import com.simiacryptus.skyenet.apps.parse.DocumentRecord -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.util.TensorflowProjector -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager -import com.simiacryptus.skyenet.webui.session.SocketManager -import org.slf4j.LoggerFactory -import kotlin.jvm.java - -class CreateProjectorFromQueryIndexAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent): Boolean { - if (!super.isEnabled(event)) return false - if (!AppSettingsState.instance.devActions) return false - val selectedFiles = UITools.getSelectedFiles(event) - val processableFiles = selectedFiles.flatMap { file -> - when { - file.isDirectory -> file.findRecursively { it.name.endsWith(".index.data") } - file.name.endsWith(".index.data") -> listOf(file) - else -> emptyList() - } - } - return processableFiles.isNotEmpty() - } - - override fun handle(e: AnActionEvent) { - val selectedFiles = UITools.getSelectedFiles(e) - val processableFiles = selectedFiles.flatMap { file -> - when { - file.isDirectory -> file.findRecursively { it.name.endsWith(".index.data") } - file.name.endsWith(".index.data") -> listOf(file) - else -> emptyList() - } - } - if (processableFiles.isEmpty()) { - UITools.showErrorDialog(e.project, "Please select a valid query index file (.index.data).", "Invalid Selection") - return - } - - ProgressManager.getInstance().run(object : Task.Backgroundable(e.project, "Creating Projector") { - override fun run(indicator: ProgressIndicator) { - try { - indicator.isIndeterminate = false - indicator.fraction = 0.0 - - val records = processableFiles.flatMap { DocumentRecord.readBinary(it.path) } - val sessionID = Session.newGlobalID() - - ApplicationServer.appInfoMap[sessionID] = AppInfoData( - applicationName = "Projector", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - - SessionProxyServer.Companion.chats[sessionID] = object : ApplicationServer( - applicationName = "Projector", - path = "/projector", - showMenubar = false, - ) { - override fun newSession( - user: User?, - session: Session - ): SocketManager { - val socketManager = super.newSession(user, session) - val ui = (socketManager as ApplicationSocketManager).applicationInterface - val projector = TensorflowProjector(api, dataStorage, sessionID, ui, null) - val result = projector.writeTensorflowEmbeddingProjectorHtmlFromRecords(records) - val task = ui.newTask(true) - task.complete(result) - return socketManager - } - } - - indicator.fraction = 1.0 - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$sessionID") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - - } catch (ex: Exception) { - log.error("Error during projector creation", ex) - UITools.showErrorDialog(e.project, "Error during projector creation: ${ex.message}", "Projector Creation Failed") - } - } - }) - } - - companion object { - private val log = LoggerFactory.getLogger(CreateProjectorFromQueryIndexAction::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/DocumentDataExtractorAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/DocumentDataExtractorAction.kt deleted file mode 100644 index 341dd714..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/DocumentDataExtractorAction.kt +++ /dev/null @@ -1,120 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.knowledge - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.actions.generic.toFile -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.github.simiacryptus.aicoder.util.findRecursively -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.apps.parse.DocumentParserApp -import com.simiacryptus.skyenet.apps.parse.DocumentParsingModel -import com.simiacryptus.skyenet.apps.parse.ParsingModel -import com.simiacryptus.skyenet.apps.parse.ParsingModel.DocumentData -import com.simiacryptus.skyenet.apps.parse.ParsingModelType -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.file.DataStorage -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import org.slf4j.LoggerFactory -import java.io.File -import java.nio.file.Path - -class DocumentDataExtractorAction : BaseAction() { - val path = "/pdfExtractor" - private var settings = DocumentParserApp.Settings() - private var modelType = ParsingModelType.Document - - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent): Boolean { - if (!super.isEnabled(event)) return false - if (!AppSettingsState.instance.devActions) return false - val selectedFiles = UITools.getSelectedFiles(event) - val processableFiles = selectedFiles.flatMap { file -> - when { - file.isDirectory -> file.findRecursively { isValidFileType(it.name) } - isValidFileType(file.name) -> listOf(file) - else -> emptyList() - } - } - return processableFiles.isNotEmpty() - } - - fun isValidFileType(filename: String): Boolean = when { - filename.endsWith(".parsed.json", ignoreCase = true) -> false - filename.endsWith(".data", ignoreCase = true) -> false - filename.endsWith(".pdf", ignoreCase = true) -> true - filename.endsWith(".txt", ignoreCase = true) -> true - filename.endsWith(".html", ignoreCase = true) -> true - filename.endsWith(".htm", ignoreCase = true) -> true - filename.endsWith(".md", ignoreCase = true) -> true - else -> true // Allow other files for code parsing - } - - override fun handle(e: AnActionEvent) { - val selectedFiles = UITools.getSelectedFiles(e) - val processableFiles = selectedFiles.flatMap { file -> - when { - file.isDirectory -> file.findRecursively { isValidFileType(it.name) } - isValidFileType(file.name) -> listOf(file) - else -> emptyList() - } - } - if (processableFiles.isEmpty()) { - UITools.showErrorDialog(e.project, "No valid files found in selection.", "No Valid Files") - return - } - val selectedFile = processableFiles.first() - val configDialog = DocumentDataExtractorConfigDialog(e.project, settings, modelType) - if (!configDialog.showAndGet()) return - settings = configDialog.settings - modelType = configDialog.modelType as ParsingModelType - - val session = Session.newGlobalID() - DataStorage.sessionPaths[session] = selectedFile.toFile.parentFile - - val smartModel = AppSettingsState.instance.smartModel.chatModel() - val parsingModel = ParsingModelType.getImpl(smartModel, 0.1, modelType) - - SessionProxyServer.chats[session] = object : DocumentParserApp( - applicationName = "Document Extractor", - path = this@DocumentDataExtractorAction.path, - api = this@DocumentDataExtractorAction.api, - fileInputs = processableFiles.map { it.toNioPath() }, - parsingModel = parsingModel as ParsingModel, - fastMode = settings.fastMode, - ) { - override fun initSettings(session: Session): T = this@DocumentDataExtractorAction.settings as T - override val root: File get() = selectedFile.parent.toFile - } - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(e.project) - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - BaseAction.log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - BaseAction.log.warn("Error opening browser", e) - } - }.start() - } - - companion object { - private val log = LoggerFactory.getLogger(DocumentDataExtractorAction::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/DocumentDataExtractorConfigDialog.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/DocumentDataExtractorConfigDialog.kt deleted file mode 100644 index 2bb492a5..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/DocumentDataExtractorConfigDialog.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.knowledge - -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.ui.components.JBCheckBox -import com.intellij.ui.components.JBTextField -import com.simiacryptus.skyenet.apps.parse.DocumentParserApp -import com.simiacryptus.skyenet.apps.parse.ParsingModelType -import javax.swing.* - -class DocumentDataExtractorConfigDialog( - project: Project?, - var settings: DocumentParserApp.Settings, - var modelType: ParsingModelType<*> -) : DialogWrapper(project) { - - private val dpiField = JBTextField(settings.dpi.toString()) - private val maxPagesField = JBTextField(settings.maxPages.toString()) - private val outputFormatField = JBTextField(settings.outputFormat) - private val pagesPerBatchField = JBTextField(settings.pagesPerBatch.toString()) - private val showImagesCheckbox = JBCheckBox("Show Images", settings.showImages) - private val saveImageFilesCheckbox = JBCheckBox("Save Image Files", settings.saveImageFiles) - private val saveTextFilesCheckbox = JBCheckBox("Save Text Files", settings.saveTextFiles) - private val saveFinalJsonCheckbox = JBCheckBox("Save Final JSON", settings.saveFinalJson) - private val fastModeCheckbox = JBCheckBox("Fast Mode", settings.fastMode) - private val addLineNumbersCheckbox = JBCheckBox("Add Line Numbers", settings.addLineNumbers) - private val modelTypeComboBox = JComboBox(ParsingModelType.values().toTypedArray()).apply { - selectedItem = modelType - } - - init { - init() - title = "Configure Document Data Extractor" - } - - override fun createCenterPanel(): JComponent { - val panel = JPanel() - panel.layout = BoxLayout(panel, BoxLayout.Y_AXIS) - panel.add(createLabeledField("Parsing Model:", modelTypeComboBox)) - panel.add(createLabeledField("DPI:", dpiField)) - panel.add(createLabeledField("Max Pages:", maxPagesField)) - panel.add(createLabeledField("Output Format:", outputFormatField)) - panel.add(createLabeledField("Pages Per Batch:", pagesPerBatchField)) - panel.add(showImagesCheckbox) - panel.add(saveImageFilesCheckbox) - panel.add(saveTextFilesCheckbox) - panel.add(saveFinalJsonCheckbox) - panel.add(fastModeCheckbox) - panel.add(addLineNumbersCheckbox) - - return panel - } - - private fun createLabeledField(label: String, field: JComponent): JPanel { - val panel = JPanel() - panel.layout = BoxLayout(panel, BoxLayout.X_AXIS) - panel.add(JLabel(label)) - panel.add(Box.createHorizontalStrut(10)) - panel.add(field) - return panel - } - - override fun doOKAction() { - settings = DocumentParserApp.Settings( - dpi = dpiField.text.toFloatOrNull() ?: settings.dpi, - maxPages = maxPagesField.text.toIntOrNull() ?: settings.maxPages, - outputFormat = outputFormatField.text, - pagesPerBatch = pagesPerBatchField.text.toIntOrNull() ?: settings.pagesPerBatch, - showImages = showImagesCheckbox.isSelected, - saveImageFiles = saveImageFilesCheckbox.isSelected, - saveTextFiles = saveTextFilesCheckbox.isSelected, - saveFinalJson = saveFinalJsonCheckbox.isSelected, - fastMode = fastModeCheckbox.isSelected, - addLineNumbers = addLineNumbersCheckbox.isSelected - ) - modelType = modelTypeComboBox.selectedItem as ParsingModelType<*> - super.doOKAction() - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/GoogleSearchAndDownloadAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/GoogleSearchAndDownloadAction.kt deleted file mode 100644 index 974dfad4..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/GoogleSearchAndDownloadAction.kt +++ /dev/null @@ -1,103 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.knowledge - -import com.github.simiacryptus.aicoder.actions.FileContextAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.Name -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.simiacryptus.util.JsonUtil -import org.apache.commons.io.FileUtils -import java.io.File -import java.net.URI -import java.net.URLEncoder -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse -import javax.swing.JTextField - -class GoogleSearchAndDownloadAction : FileContextAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - class SettingsUI { - @Name("Search Query") - var searchQuery: JTextField = JTextField("", 40) - } - - class UserSettings( - var searchQuery: String = "" - ) - - class Settings( - val settings: UserSettings? = null, - val project: Project? = null - ) - - override fun isEnabled(event: AnActionEvent): Boolean { - return super.isEnabled(event) - && !AppSettingsState.instance.googleApiKey.isNullOrBlank() - && !AppSettingsState.instance.googleSearchEngineId.isNullOrBlank() - && AppSettingsState.instance.devActions - } - - override fun getConfig(project: Project?, e: AnActionEvent): Settings { - return Settings( - UITools.showDialog( - project, - SettingsUI::class.java, - UserSettings::class.java, - "Google Search and Download" - ), - project - ) - } - - override fun processSelection(state: SelectionState, config: Settings?, progress: ProgressIndicator): Array { - val searchQuery = config?.settings?.searchQuery ?: return emptyArray() - val searchResults = performGoogleSearch(searchQuery) - return downloadResults(searchResults, state.selectedFile) - } - - private fun performGoogleSearch(query: String): List> { - val client = HttpClient.newBuilder().build() - val encodedQuery = URLEncoder.encode(query, "UTF-8") - val uriBuilder = "https://www.googleapis.com/customsearch/v1?key=${AppSettingsState.instance.googleApiKey}&cx=${AppSettingsState.instance.googleSearchEngineId}&q=$encodedQuery&num=10" - val request = HttpRequest.newBuilder().uri(URI.create(uriBuilder)).GET().build() - val response = client.send(request, HttpResponse.BodyHandlers.ofString()) - if (response.statusCode() != 200) { - throw RuntimeException("Google API request failed with status ${response.statusCode()}: ${response.body()}") - } - val searchResults: Map = JsonUtil.fromJson(response.body(), Map::class.java) - return (searchResults["items"] as List>?) ?: emptyList() - } - - private fun downloadResults(results: List>, targetDir: File): Array { - val client = HttpClient.newBuilder().build() - return results.mapIndexed { index, item -> - val url = item["link"] as String - val title = item["title"] as String - val fileName = "${index + 1}_${sanitizeFileName(title)}.html" - val targetFile = File(targetDir, fileName) - - try { - val request = HttpRequest.newBuilder().uri(URI.create(url)).GET().build() - val response = client.send(request, HttpResponse.BodyHandlers.ofString()) - if (response.statusCode() == 200) { - FileUtils.writeStringToFile(targetFile, response.body(), "UTF-8") - targetFile - } else { - null - } - } catch (e: Exception) { - e.printStackTrace() - null - } - }.filterNotNull().toTypedArray() - } - - private fun sanitizeFileName(fileName: String): String { - return fileName.replace(Regex("[^a-zA-Z0-9.-]"), "_").take(50) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/SaveAsQueryIndexAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/SaveAsQueryIndexAction.kt deleted file mode 100644 index 9f0bc454..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/knowledge/SaveAsQueryIndexAction.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.knowledge - -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.IdeaOpenAIClient -import com.github.simiacryptus.aicoder.util.UITools -import com.github.simiacryptus.aicoder.util.findRecursively -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.progress.ProgressManager -import com.intellij.openapi.progress.Task -import com.simiacryptus.skyenet.apps.parse.DocumentRecord.Companion.saveAsBinary -import com.simiacryptus.skyenet.apps.parse.ProgressState -import org.slf4j.LoggerFactory -import java.util.concurrent.Executors - -class SaveAsQueryIndexAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent): Boolean { - if (!super.isEnabled(event)) return false - if (!AppSettingsState.instance.devActions) return false - val selectedFiles = UITools.getSelectedFiles(event) - return selectedFiles.isNotEmpty() && selectedFiles.any { file -> - file.isDirectory || file.name.endsWith(".parsed.json") - } - } - - override fun handle(e: AnActionEvent) { - val selectedFiles = UITools.getSelectedFiles(e) - if (selectedFiles.isEmpty()) { - UITools.showErrorDialog(e.project, "Please select JSON files to convert.", "No Files Selected") - return - } - val jsonFiles = selectedFiles.flatMap { file -> - when { - file.isDirectory -> file.findRecursively { it.name.endsWith(".parsed.json") } - file.name.endsWith(".parsed.json") -> listOf(file) - else -> emptyList() - } - } - if (jsonFiles.isEmpty()) { - UITools.showErrorDialog(e.project, "No .parsed.json files found in selection.", "No Valid Files") - return - } - ProgressManager.getInstance().run(object : Task.Backgroundable(e.project, "Indexing Vectors", false) { - override fun run(indicator: ProgressIndicator) { - val threadPool = Executors.newFixedThreadPool(8) - try { - indicator.isIndeterminate = false - indicator.fraction = 0.0 - saveAsBinary( - openAIClient = IdeaOpenAIClient.instance, - pool = threadPool, - progressState = ProgressState().apply { - onUpdate += { - indicator.fraction = it.progress / it.max - } - }, - inputPaths = jsonFiles.map { it.path }.toTypedArray() - ) - indicator.fraction = 1.0 - log.info("Conversion to Data complete") - } catch (ex: Exception) { - log.error("Error during binary conversion", ex) - UITools.showErrorDialog(e.project, "Error during conversion: ${ex.message}", "Conversion Failed") - } finally { - threadPool.shutdown() - } - } - }) - } - - - companion object { - private val log = LoggerFactory.getLogger(SaveAsQueryIndexAction::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/AppendTextWithChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/AppendTextWithChatAction.kt deleted file mode 100644 index 5e2d1b36..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/AppendTextWithChatAction.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.legacy - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.ApiModel.* -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.util.ClientUtil.toContentList - -class AppendTextWithChatAction : SelectionAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions - - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(state: SelectionState, config: String?): String { - val settings = AppSettingsState.instance - val request = ChatRequest( - model = settings.smartModel, - temperature = settings.temperature - ).copy( - temperature = settings.temperature, - messages = listOf( - ChatMessage(Role.system, "Append text to the end of the user's prompt".toContentList(), null), - ChatMessage(Role.user, state.selectedText.toString().toContentList(), null) - ), - ) - val chatResponse = api.chat(request, settings.smartModel.chatModel()) - val b4 = state.selectedText ?: "" - val str = chatResponse.choices[0].message?.content ?: "" - return b4 + if (str.startsWith(b4)) str.substring(b4.length) else str - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/CommentsAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/CommentsAction.kt deleted file mode 100644 index 03541b52..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/CommentsAction.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.legacy - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.LanguageUtils -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy - -class CommentsAction : SelectionAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions - - override fun getConfig(project: Project?): String { - return "" - } - - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - return LanguageUtils.isLanguageSupported(computerLanguage) - } - - override fun processSelection(state: SelectionState, config: String?): String { - return ChatProxy( - clazz = CommentsAction_VirtualAPI::class.java, - api = api, - temperature = AppSettingsState.instance.temperature, - model = AppSettingsState.instance.smartModel.chatModel(), - deserializerRetries = 5 - ).create().editCode( - state.selectedText ?: "", - "Add comments to each line explaining the code", - state.language.toString(), - AppSettingsState.instance.humanLanguage - ).code ?: "" - } - - interface CommentsAction_VirtualAPI { - fun editCode( - code: String, - operations: String, - computerLanguage: String, - humanLanguage: String - ): CommentsAction_ConvertedText - - class CommentsAction_ConvertedText { - var code: String? = null - var language: String? = null - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/DocAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/DocAction.kt deleted file mode 100644 index d96af2fb..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/DocAction.kt +++ /dev/null @@ -1,95 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.legacy - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.IndentedText -import com.github.simiacryptus.aicoder.util.psi.PsiUtil -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy - -class DocAction : SelectionAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions - - interface DocAction_VirtualAPI { - fun processCode( - code: String, - operation: String, - computerLanguage: String, - humanLanguage: String - ): DocAction_ConvertedText - - class DocAction_ConvertedText { - var text: String? = null - var language: String? = null - } - } - - private val proxy: DocAction_VirtualAPI by lazy { - val chatProxy = ChatProxy( - clazz = DocAction_VirtualAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ) - chatProxy.addExample( - DocAction_VirtualAPI.DocAction_ConvertedText().apply { - text = """ - /** - * Prints "Hello, world!" to the console - */ - """.trimIndent() - language = "English" - } - ) { - it.processCode( - """ - fun hello() { - println("Hello, world!") - } - """.trimIndent(), - "Write detailed KDoc prefix for code block", - "Kotlin", - "English" - ) - } - chatProxy.create() - } - - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(state: SelectionState, config: String?): String { - val code = state.selectedText - val indentedInput = IndentedText.fromString(code.toString()) - val docString = proxy.processCode( - indentedInput.textBlock.toString(), - "Write detailed " + (state.language?.docStyle ?: "documentation") + " prefix for code block", - state.language?.name ?: "", - AppSettingsState.instance.humanLanguage - ).text ?: "" - return docString + code - } - - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - if (computerLanguage == ComputerLanguage.Text) return false - if (computerLanguage?.docStyle == null) return false - if (computerLanguage.docStyle.isBlank()) return false - return true - } - - override fun editSelection(state: EditorState, start: Int, end: Int): Pair { - if (state.psiFile == null) return super.editSelection(state, start, end) - val codeBlock = PsiUtil.getCodeElement(state.psiFile, start, end) - if (codeBlock == null) return super.editSelection(state, start, end) - val textRange = codeBlock.textRange - return Pair(textRange.startOffset, textRange.endOffset) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ImplementStubAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ImplementStubAction.kt deleted file mode 100644 index 99c1f8dc..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ImplementStubAction.kt +++ /dev/null @@ -1,87 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.legacy - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.psi.PsiUtil -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy -import com.simiacryptus.util.StringUtil -import java.util.* - -class ImplementStubAction : SelectionAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions - - interface VirtualAPI { - fun editCode( - code: String, - operation: String, - computerLanguage: String, - humanLanguage: String - ): ConvertedText - - class ConvertedText { - var code: String? = null - var language: String? = null - } - } - - private fun getProxy(): VirtualAPI { - return ChatProxy( - clazz = VirtualAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ).create() - } - - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - if (computerLanguage == null) return false - return computerLanguage != ComputerLanguage.Text - } - - override fun defaultSelection(editorState: EditorState, offset: Int): Pair { - val codeRanges = editorState.contextRanges.filter { PsiUtil.matchesType(it.name, PsiUtil.ELEMENTS_CODE) } - if (codeRanges.isEmpty()) return editorState.line - return codeRanges.minByOrNull { it.length() }?.range() ?: editorState.line - } - - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(state: SelectionState, config: String?): String { - val code = state.selectedText ?: "" - val settings = AppSettingsState.instance - val outputHumanLanguage = settings.humanLanguage - val computerLanguage = state.language - - val codeContext = state.contextRanges.filter { - PsiUtil.matchesType( - it.name, - PsiUtil.ELEMENTS_CODE - ) - } - var smallestIntersectingMethod = "" - if (codeContext.isNotEmpty()) smallestIntersectingMethod = - codeContext.minByOrNull { it.length() }?.subString(state.entireDocument ?: "") ?: "" - - var declaration = code - declaration = StringUtil.stripSuffix(declaration.trim(), smallestIntersectingMethod) - declaration = declaration.trim() - - return getProxy().editCode( - declaration, - "Implement Stub", - computerLanguage?.name?.lowercase(Locale.ROOT) ?: "", - outputHumanLanguage - ).code ?: "" - } - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/InsertImplementationAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/InsertImplementationAction.kt deleted file mode 100644 index 8ce6f94f..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/InsertImplementationAction.kt +++ /dev/null @@ -1,133 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.legacy - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.TextBlock -import com.github.simiacryptus.aicoder.util.UITools -import com.github.simiacryptus.aicoder.util.psi.PsiClassContext -import com.github.simiacryptus.aicoder.util.psi.PsiUtil -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.application.runReadAction -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy - -class InsertImplementationAction : SelectionAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions - - interface VirtualAPI { - fun implementCode( - specification: String, - prefix: String, - computerLanguage: String, - humanLanguage: String - ): ConvertedText - - class ConvertedText { - var code: String? = null - var language: String? = null - } - } - - private fun getProxy(): VirtualAPI { - return ChatProxy( - clazz = VirtualAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ).create() - } - - override fun getConfig(project: Project?): String { - return "" - } - - override fun defaultSelection(editorState: EditorState, offset: Int): Pair { - val foundItem = editorState.contextRanges.filter { - PsiUtil.matchesType( - it.name, - PsiUtil.ELEMENTS_COMMENTS - ) - }.minByOrNull { it.length() } - return foundItem?.range() ?: editorState.line - } - - override fun editSelection(state: EditorState, start: Int, end: Int): Pair { - val foundItem = state.contextRanges.filter { - PsiUtil.matchesType( - it.name, - PsiUtil.ELEMENTS_COMMENTS - ) - }.minByOrNull { it.length() } - return foundItem?.range() ?: Pair(start, end) - } - - override fun processSelection(state: SelectionState, config: String?): String { - val humanLanguage = AppSettingsState.instance.humanLanguage - val computerLanguage = state.language - val psiClassContextActionParams = getPsiClassContextActionParams(state) - val selectedText = state.selectedText ?: "" - - val comment = psiClassContextActionParams.largestIntersectingComment - var instruct = comment?.subString(state.entireDocument ?: "")?.trim() ?: selectedText - if (selectedText.split(" ").dropWhile { it.isEmpty() }.size > 4) { - instruct = selectedText.trim() - } - val fromString: TextBlock? = computerLanguage?.getCommentModel(instruct)?.fromString(instruct) - val specification = fromString?.rawString()?.map { it.toString().trim() } - ?.filter { it.isNotEmpty() }?.reduce { a, b -> "$a $b" } ?: return selectedText - val code = if (state.psiFile != null) { - UITools.run(state.project, "Insert Implementation", true, true) { - val psiClassContext = runReadAction { - PsiClassContext.getContext( - state.psiFile, - psiClassContextActionParams.selectionStart, - psiClassContextActionParams.selectionEnd, - computerLanguage - ).toString() - } - getProxy().implementCode( - specification, - psiClassContext, - computerLanguage.name, - humanLanguage - ).code - } - } else { - getProxy().implementCode( - specification, - "", - computerLanguage.name, - humanLanguage - ).code - } - return if (code != null) "$selectedText\n${state.indent}$code" else selectedText - } - - private fun getPsiClassContextActionParams(state: SelectionState): PsiClassContextActionParams { - val selectionStart = state.selectionOffset - return PsiClassContextActionParams( - selectionStart, - selectionStart + (state.selectionLength ?: 0), - state.contextRanges.find { PsiUtil.matchesType(it.name, PsiUtil.ELEMENTS_COMMENTS) } - ) - } - - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - if (computerLanguage == null || computerLanguage == ComputerLanguage.Text || computerLanguage == ComputerLanguage.Markdown) { - return false - } - return super.isLanguageSupported(computerLanguage) - } - - private class PsiClassContextActionParams( - val selectionStart: Int, - val selectionEnd: Int, - val largestIntersectingComment: ContextRange? - ) -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/RenameVariablesAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/RenameVariablesAction.kt deleted file mode 100644 index 6ee6a838..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/RenameVariablesAction.kt +++ /dev/null @@ -1,85 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.legacy - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.LanguageUtils -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy - -open class RenameVariablesAction : SelectionAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions - - interface RenameAPI { - fun suggestRenames( - code: String, - computerLanguage: String, - humanLanguage: String - ): SuggestionResponse - - class SuggestionResponse { - var suggestions: MutableList = mutableListOf() - - class Suggestion { - var originalName: String? = null - var suggestedName: String? = null - } - } - } - - val proxy: RenameAPI - get() { - return ChatProxy( - clazz = RenameAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ).create() - } - - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(event: AnActionEvent?, state: SelectionState, config: String?): String { - val renameSuggestions = UITools.run(event?.project, templateText, true, true) { - proxy - .suggestRenames( - state.selectedText ?: "", - state.language?.name ?: "", - AppSettingsState.instance.humanLanguage - ) - .suggestions - .filter { it.originalName != null && it.suggestedName != null } - .associate { it.originalName!! to it.suggestedName!! } - } - val selectedSuggestions = choose(renameSuggestions) - return UITools.run(event?.project, templateText, true, true) { - var selectedText = state.selectedText - val filter = renameSuggestions.filter { it.key in selectedSuggestions } - filter.forEach { (key, value) -> - selectedText = selectedText?.replace(key, value) - } - selectedText ?: "" - } - } - - open fun choose(renameSuggestions: Map): Set { - return UITools.showCheckboxDialog( - "Select which items to rename", - renameSuggestions.keys.toTypedArray(), - renameSuggestions.map { (key, value) -> "$key -> $value" }.toTypedArray() - ).toSet() - } - - override fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - return LanguageUtils.isLanguageSupported(computerLanguage) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ReplaceWithSuggestionsAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ReplaceWithSuggestionsAction.kt deleted file mode 100644 index f182ec9c..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/ReplaceWithSuggestionsAction.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.legacy - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy -import com.simiacryptus.util.StringUtil -import kotlin.math.ceil -import kotlin.math.ln -import kotlin.math.pow - -open class ReplaceWithSuggestionsAction : SelectionAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun isEnabled(event: AnActionEvent) = AppSettingsState.instance.enableLegacyActions - - interface VirtualAPI { - fun suggestText(template: String, examples: List): Suggestions - - class Suggestions { - var choices: List? = null - } - } - - val proxy: VirtualAPI - get() { - return ChatProxy( - clazz = VirtualAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ).create() - } - - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(event: AnActionEvent?, state: SelectionState, config: String?): String { - val choices = UITools.run(event?.project, templateText, true, true) { - val selectedText = state.selectedText - val idealLength = 2.0.pow(2 + ceil(ln(selectedText?.length?.toDouble() ?: 1.0))).toInt() - val selectionStart = state.selectionOffset - val allBefore = state.entireDocument?.substring(0, selectionStart) ?: "" - val selectionEnd = state.selectionOffset + (state.selectionLength ?: 0) - val allAfter = state.entireDocument?.substring(selectionEnd, state.entireDocument.length) ?: "" - val before = StringUtil.getSuffixForContext(allBefore, idealLength).toString().replace('\n', ' ') - val after = StringUtil.getPrefixForContext(allAfter, idealLength).toString().replace('\n', ' ') - proxy.suggestText( - "$before _____ $after", - listOf(selectedText.toString()) - ).choices - } - return choose(choices ?: listOf()) - } - - open fun choose(choices: List): String { - return UITools.showRadioButtonDialog("Select an option to fill in the blank:", *choices.toTypedArray()) - ?.toString() ?: "" - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/VoiceToTextAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/VoiceToTextAction.kt deleted file mode 100644 index 7d036809..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/legacy/VoiceToTextAction.kt +++ /dev/null @@ -1,140 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.legacy - -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.command.WriteCommandAction -import com.simiacryptus.jopenai.audio.AudioRecorder -import com.simiacryptus.jopenai.audio.LookbackLoudnessWindowBuffer -import org.slf4j.LoggerFactory -import java.util.* -import java.util.concurrent.ConcurrentLinkedDeque -import java.util.concurrent.Executors -import java.util.concurrent.Future -import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicInteger -import javax.sound.sampled.AudioSystem -import javax.sound.sampled.TargetDataLine -import javax.swing.JFrame -import javax.swing.JLabel - -class VoiceToTextAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(e: AnActionEvent) { - val continueFn = statusDialog(e)::isVisible - - val rawBuffer = ConcurrentLinkedDeque() - Thread({ - try { - log.warn("Recording thread started") - AudioRecorder(rawBuffer, 0.05, continueFn).run() - log.warn("Recording thread complete") - } catch (e: Throwable) { - UITools.error(log, "Error", e) - } - }, "dication-audio-recorder").start() - - val wavBuffer = ConcurrentLinkedDeque() - Thread({ - log.warn("Audio processing thread started") - try { - LookbackLoudnessWindowBuffer(rawBuffer, wavBuffer, continueFn).run() - } catch (e: Throwable) { - UITools.error(log, "Error", e) - } - log.warn("Audio processing thread complete") - }, "dictation-audio-processor").start() - - val caretModel = (e.getData(CommonDataKeys.EDITOR) ?: return).caretModel - val primaryCaret = caretModel.primaryCaret - val dictationPump = if (primaryCaret.hasSelection()) { - DictationPump(e, wavBuffer, continueFn, primaryCaret.selectionEnd, primaryCaret.selectedText ?: "") - } else { - DictationPump(e, wavBuffer, continueFn, caretModel.offset) - } - Thread({ - log.warn("Speech-To-Text thread started") - try { - dictationPump.run() - } catch (e: Throwable) { - UITools.error(log, "Error", e) - } - log.warn("Speech-To-Text thread complete") - }, "dictation-api-processor").start() - } - - private inner class DictationPump( - val event: AnActionEvent, - private val audioBuffer: Deque, - val continueFn: () -> Boolean, - offsetStart: Int, - var prompt: String = "" - ) { - - private val offset: AtomicInteger = AtomicInteger(offsetStart) - - fun run() { - while (this.continueFn() || audioBuffer.isNotEmpty()) { - val recordAudio = audioBuffer.poll() - if (null == recordAudio) { - Thread.sleep(1) - } else { - log.warn("Speech-To-Text Starting...") - var text = api2.transcription(recordAudio, prompt) - if (prompt.isNotEmpty()) text = " $text" - val newPrompt = (prompt + text).split(" ").takeLast(32).joinToString(" ") - log.warn( - """Speech-To-Text Complete - | Prompt: $prompt - | Result: $text""".trimMargin() - ) - prompt = newPrompt - WriteCommandAction.runWriteCommandAction(event.project) { - val editor = event.getData(CommonDataKeys.EDITOR) ?: return@runWriteCommandAction - editor.document.insertString(offset.getAndAdd(text.length), text) - } - } - } - } - } - - - private fun statusDialog(e1: AnActionEvent): JFrame { - val dialog = JFrame("Dictation") - val jLabel = JLabel("Close this window to stop recording and dictation") - jLabel.font = jLabel.font.deriveFont(48f) - dialog.add(jLabel) - dialog.pack() - dialog.location = e1.getData(PlatformDataKeys.CONTEXT_COMPONENT)?.locationOnScreen!! - dialog.isAlwaysOnTop = true - dialog.isVisible = true - return dialog - } - - override fun isEnabled(event: AnActionEvent): Boolean { - if (!AppSettingsState.instance.enableLegacyActions) return false - return try { - null != targetDataLine.get(50, TimeUnit.MILLISECONDS) - } catch (e: Exception) { - false - } - } - - companion object { - private val log = LoggerFactory.getLogger(VoiceToTextAction::class.java) - - private val pool = Executors.newFixedThreadPool(1) - - val targetDataLine: Future by lazy { - pool.submit { - AudioSystem.getTargetDataLine(AudioRecorder.audioFormat) - } - } - } - -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownImplementActionGroup.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownImplementActionGroup.kt deleted file mode 100644 index b40c22e5..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownImplementActionGroup.kt +++ /dev/null @@ -1,86 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.markdown - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionGroup -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.project.Project -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy - -class MarkdownImplementActionGroup : ActionGroup() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - private val markdownLanguages = listOf( - "sql", "java", "asp", "c", "clojure", "coffee", "cpp", "csharp", "css", "bash", "go", "java", "javascript", - "less", "make", "matlab", "objectivec", "pascal", "PHP", "Perl", "python", "rust", "scss", "sql", "svg", - "swift", "ruby", "smalltalk", "vhdl" - ) - - override fun update(e: AnActionEvent) { - e.presentation.isEnabledAndVisible = isEnabled(e) - super.update(e) - } - - companion object { - fun isEnabled(e: AnActionEvent): Boolean { - val computerLanguage = ComputerLanguage.getComputerLanguage(e) ?: return false - if (ComputerLanguage.Markdown != computerLanguage) return false - return UITools.hasSelection(e) - } - } - - override fun getChildren(e: AnActionEvent?): Array { - if (e == null) return emptyArray() - val computerLanguage = ComputerLanguage.getComputerLanguage(e) ?: return emptyArray() - val actions = markdownLanguages.map { language -> MarkdownImplementAction(language) } - return actions.toTypedArray() - } - - open class MarkdownImplementAction(private val language: String) : SelectionAction(true) { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - init { - templatePresentation.text = language - templatePresentation.description = language - } - - interface ConversionAPI { - fun implement(text: String, humanLanguage: String, computerLanguage: String): ConvertedText - - class ConvertedText { - var code: String? = null - var language: String? = null - } - } - - private fun getProxy(): ConversionAPI { - return ChatProxy( - clazz = ConversionAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - temperature = AppSettingsState.instance.temperature, - deserializerRetries = 5 - ).create() - } - - override fun getConfig(project: Project?): String { - return "" - } - - override fun processSelection(state: SelectionState, config: String?): String { - val code = getProxy().implement(state.selectedText ?: "", "autodetect", language).code ?: "" - return """ - | - | - |```$language - |${code.let { /*escapeHtml4*/(it)/*.indent(" ")*/ }} - |``` - | - |""".trimMargin() - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownListAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownListAction.kt deleted file mode 100644 index 54f16208..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/markdown/MarkdownListAction.kt +++ /dev/null @@ -1,111 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.markdown - -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.github.simiacryptus.aicoder.util.UITools -import com.github.simiacryptus.aicoder.util.UITools.getIndent -import com.github.simiacryptus.aicoder.util.UITools.insertString -import com.github.simiacryptus.aicoder.util.psi.PsiUtil.getAll -import com.github.simiacryptus.aicoder.util.psi.PsiUtil.getSmallestIntersecting -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.application.ApplicationManager -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.jopenai.proxy.ChatProxy -import com.simiacryptus.util.StringUtil - -class MarkdownListAction : BaseAction() { - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - interface ListAPI { - fun newListItems( - items: List?, - count: Int, - ): Items - - data class Items( - val items: List? = null, - ) - } - - val proxy: ListAPI - get() { - val chatProxy = ChatProxy( - clazz = ListAPI::class.java, - api = api, - model = AppSettingsState.instance.smartModel.chatModel(), - deserializerRetries = 5, - ) - chatProxy.addExample( - returnValue = ListAPI.Items( - items = listOf("Item 4", "Item 5", "Item 6") - ) - ) { - it.newListItems( - items = listOf("Item 1", "Item 2", "Item 3"), - count = 6 - ) - } - return chatProxy.create() - } - - override fun handle(e: AnActionEvent) { - val caret = e.getData(CommonDataKeys.CARET) ?: return - val psiFile = e.getData(CommonDataKeys.PSI_FILE) ?: return - val list = - getSmallestIntersecting(psiFile, caret.selectionStart, caret.selectionEnd, "MarkdownListImpl") ?: return - val items = StringUtil.trim( - getAll(list, "MarkdownListItemImpl") - .map { - val all = getAll(it, "MarkdownParagraphImpl") - if (all.isEmpty()) it.text else all[0].text - }.toList(), 10, false - ) - val indent = getIndent(caret) - val endOffset = list.textRange.endOffset - val bulletTypes = listOf("- [ ] ", "- ", "* ") - val document = (e.getData(CommonDataKeys.EDITOR) ?: return).document - val rawItems = items.map(CharSequence::trim).map { - val bulletType = bulletTypes.find(it::startsWith) - if (null != bulletType) StringUtil.stripPrefix(it, bulletType).toString() - else it.toString() - } - - UITools.redoableTask(e) { - var newItems: List? = null - UITools.run( - e.project, "Generating New Items", true - ) { - newItems = proxy.newListItems( - rawItems, - (items.size * 2) - ).items - } - var newList = "" - ApplicationManager.getApplication().runReadAction { - val strippedList = list.text.split("\n") - .map(String::trim).filter(String::isNotEmpty) - .joinToString("\n") - val bulletString = bulletTypes.find(strippedList::startsWith) ?: "1. " - newList = newItems?.joinToString("\n") { indent.toString() + bulletString + it } ?: "" - } - UITools.writeableFn(e) { - insertString(document, endOffset, "\n" + newList) - } - } - } - - override fun isEnabled(event: AnActionEvent): Boolean { - val computerLanguage = ComputerLanguage.getComputerLanguage(event) ?: return false - if (ComputerLanguage.Markdown != computerLanguage) return false - val caret = event.getData(CommonDataKeys.CARET) ?: return false - val psiFile = event.getData(CommonDataKeys.PSI_FILE) ?: return false - getSmallestIntersecting(psiFile, caret.selectionStart, caret.selectionEnd, "MarkdownListImpl") ?: return false - return true - } -} - - - diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/AutoPlanChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/AutoPlanChatAction.kt deleted file mode 100644 index 13291211..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/AutoPlanChatAction.kt +++ /dev/null @@ -1,131 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.plan - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.actions.generic.SimpleCommandAction.Companion.tripleTilde -import com.github.simiacryptus.aicoder.actions.generic.toFile -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.diff.FileValidationUtils -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.apps.general.AutoPlanChatApp -import com.simiacryptus.skyenet.apps.plan.PlanSettings -import com.simiacryptus.skyenet.apps.plan.PlanUtil.isWindows -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.file.DataStorage -import com.simiacryptus.skyenet.core.util.getModuleRootForFile -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import org.slf4j.LoggerFactory -import java.io.File -import java.nio.file.Path - -class AutoPlanChatAction : BaseAction() { - - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(e: AnActionEvent) { - val dialog = PlanAheadConfigDialog( - e.project, PlanSettings( - defaultModel = AppSettingsState.instance.smartModel.chatModel(), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - command = listOf( - if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" - ), - temperature = AppSettingsState.instance.temperature, - workingDir = UITools.getRoot(e), - env = mapOf(), - githubToken = AppSettingsState.instance.githubToken, - googleApiKey = AppSettingsState.instance.googleApiKey, - googleSearchEngineId = AppSettingsState.instance.googleSearchEngineId, - ) - ) - if (dialog.showAndGet()) { - // Settings are applied only if the user clicks OK - val session = Session.newGlobalID() - val folder = UITools.getSelectedFolder(e) - val root = folder?.toFile ?: getModuleRootForFile( - UITools.getSelectedFile(e)?.parent?.toFile ?: throw RuntimeException("") - ) - DataStorage.sessionPaths[session] = root - SessionProxyServer.Companion.chats[session] = object : AutoPlanChatApp( - planSettings = dialog.settings.copy( - env = mapOf(), - workingDir = root.absolutePath, - language = if (isWindows) "powershell" else "bash", - command = listOf( - if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" - ), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - ), - model = AppSettingsState.instance.smartModel.chatModel(), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - showMenubar = false, - api = api, - api2 = api2, - ) { - fun codeFiles() = (UITools.getSelectedFiles(e).toTypedArray()?.toList()?.flatMap { - FileValidationUtils.expandFileList(it.toFile).toList() - }?.map { it.toPath() }?.toSet()?.toMutableSet() ?: mutableSetOf()) - .filter { it.toFile().exists() } - .filter { it.toFile().length() < 1024 * 1024 / 2 } - .map { root.toPath().relativize(it) ?: it }.toSet() - - fun codeSummary() = codeFiles() - .joinToString("\n\n") { path -> - """ - |# ${path} - |$tripleTilde${path.toString().split('.').lastOrNull()} - |${root.resolve(path.toFile()).readText(Charsets.UTF_8)} - |$tripleTilde - """.trimMargin() - } - - fun projectSummary() = codeFiles() - .asSequence().distinct().sorted() - .joinToString("\n") { path -> - "* ${path} - ${root.resolve(path.toFile()).length()} bytes" - } - - override fun contextData(): List = listOf( - if (codeFiles().size < 4) { - "Files:\n" + codeSummary() - } else { - "Files:\n" + projectSummary() - }, - ) - } - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Auto Plan Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - val server = AppServer.getServer(e.project) - openBrowser(server, session.toString()) - } - } - - private fun openBrowser(server: AppServer, session: String) { - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - companion object { - private val log = LoggerFactory.getLogger(AutoPlanChatAction::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PlanAheadAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PlanAheadAction.kt deleted file mode 100644 index 5f1b6ed5..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PlanAheadAction.kt +++ /dev/null @@ -1,100 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.plan - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.actions.generic.toFile -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.apps.general.PlanAheadApp -import com.simiacryptus.skyenet.apps.plan.PlanSettings -import com.simiacryptus.skyenet.apps.plan.PlanUtil.isWindows -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.file.DataStorage -import com.simiacryptus.skyenet.core.util.getModuleRootForFile -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import org.slf4j.LoggerFactory -import kotlin.collections.set - - -class PlanAheadAction : BaseAction() { - val path = "/taskDev" - - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(e: AnActionEvent) { - val dialog = PlanAheadConfigDialog( - e.project, PlanSettings( - defaultModel = AppSettingsState.instance.smartModel.chatModel(), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - command = listOf( - if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" - ), - temperature = AppSettingsState.instance.temperature, - workingDir = UITools.getRoot(e), - env = mapOf(), - githubToken = AppSettingsState.instance.githubToken, - googleApiKey = AppSettingsState.instance.googleApiKey, - googleSearchEngineId = AppSettingsState.instance.googleSearchEngineId, - ) - ) - if (dialog.showAndGet()) { - // Settings are applied only if the user clicks OK - val session = Session.newGlobalID() - val folder = UITools.getSelectedFolder(e) - val root = folder?.toFile ?: getModuleRootForFile( - UITools.getSelectedFile(e)?.parent?.toFile ?: throw RuntimeException("") - ) - DataStorage.sessionPaths[session] = root - val planSettings = dialog.settings.copy( - env = mapOf(), - workingDir = root.absolutePath, - language = if (isWindows) "powershell" else "bash", - command = listOf( - if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" - ), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - ) - SessionProxyServer.Companion.chats[session] = PlanAheadApp( - planSettings = planSettings, - model = AppSettingsState.instance.smartModel.chatModel(), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - showMenubar = false, - api = api, - api2 = api2, - ) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - val server = AppServer.getServer(e.project) - - openBrowser(server, session.toString()) - } - } - - private fun openBrowser(server: AppServer, session: String) { - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - LoggerFactory.getLogger(PlanAheadAction::class.java).warn("Error opening browser", e) - } - }.start() - } - - companion object { - private val log = LoggerFactory.getLogger(PlanAheadAction::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PlanAheadConfigDialog.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PlanAheadConfigDialog.kt deleted file mode 100644 index 65c3c1de..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PlanAheadConfigDialog.kt +++ /dev/null @@ -1,267 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.plan - -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.intellij.openapi.fileChooser.FileChooser -import com.intellij.openapi.fileChooser.FileChooserDescriptor -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.ui.components.JBScrollPane -import com.intellij.ui.table.JBTable -import com.simiacryptus.jopenai.models.ChatModel -import com.simiacryptus.skyenet.apps.plan.PlanSettings -import com.simiacryptus.skyenet.apps.plan.TaskSettings -import com.simiacryptus.skyenet.apps.plan.TaskType -import java.awt.BorderLayout -import java.awt.Component -import java.awt.Dimension -import java.awt.GridLayout -import javax.swing.* -import javax.swing.table.DefaultTableCellRenderer -import javax.swing.table.DefaultTableModel - -class PlanAheadConfigDialog( - project: Project?, - val settings: PlanSettings, -) : DialogWrapper(project) { - private val temperatureSlider = JSlider(0, 100, (settings.temperature * 100).toInt()) - private val autoFixCheckbox = JCheckBox("Auto-apply fixes", settings.autoFix) - private val allowBlockingCheckbox = JCheckBox("Allow blocking", settings.allowBlocking) - private val taskTableModel = object : DefaultTableModel(arrayOf("Enabled", "Task Type", "Model"), 0) { - override fun getColumnClass(columnIndex: Int) = when (columnIndex) { - 0 -> java.lang.Boolean::class.java - else -> super.getColumnClass(columnIndex) - } - - override fun isCellEditable(row: Int, column: Int) = column == 0 || column == 2 - } - private val taskTable = JBTable(taskTableModel).apply { putClientProperty("terminateEditOnFocusLost", true) } - - // Add a function to retrieve visible models - private fun getVisibleModels() = - ChatModel.values().map { it.value }.filter { isVisible(it) }.toList() - .sortedBy { "${it.provider.name} - ${it.modelName}" } - - // Custom renderer to display provider name and model name - private fun getModelRenderer() = object : DefaultTableCellRenderer() { - override fun getTableCellRendererComponent( - table: JTable, - value: Any, - isSelected: Boolean, - hasFocus: Boolean, - row: Int, - column: Int - ): Component { - val label = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column) as JLabel - if (value is String) { - val model = getVisibleModels().find { it.modelName == value } - label.text = "${model?.provider?.name} - $value" - } - return label - } - } - - companion object { - fun isVisible(it: ChatModel): Boolean { - val hasApiKey = - AppSettingsState.instance.apiKey?.filter { it.value.isNotBlank() }?.keys?.contains(it.provider.name) - return false != hasApiKey - } - } - - private val checkboxStates = AppSettingsState.instance.executables.map { true }.toMutableList() - private val tableModel = object : DefaultTableModel(arrayOf("Enabled", "Command"), 0) { - - init { - AppSettingsState.instance.executables.forEach { command -> - addRow(arrayOf(true, command)) - } - } - - override fun getColumnClass(columnIndex: Int) = when (columnIndex) { - 0 -> java.lang.Boolean::class.java - else -> super.getColumnClass(columnIndex) - } - - override fun isCellEditable(row: Int, column: Int) = column == 0 - - override fun setValueAt(aValue: Any?, row: Int, column: Int) { - super.setValueAt(aValue, row, column) - if (column == 0 && aValue is Boolean) { - checkboxStates[row] = aValue - } else { - throw IllegalArgumentException("Invalid column index: $column") - } - } - - override fun getValueAt(row: Int, column: Int): Any = - try { - if (column == 0) { - checkboxStates[row] - } else super.getValueAt(row, column) - } catch (e: IndexOutOfBoundsException) { - false - } - } - private val commandTable = JBTable(tableModel).apply { putClientProperty("terminateEditOnFocusLost", true) } - private val addCommandButton = JButton("Add Command") - private val editCommandButton = JButton("Edit Command") - - - init { - taskTable.columnModel.getColumn(2).apply { - preferredWidth = 200 - val modelComboBox = JComboBox(getVisibleModels().map { it.modelName }.toTypedArray()) - cellEditor = DefaultCellEditor(modelComboBox) - cellRenderer = getModelRenderer() - } - - init() - title = "Configure Plan Ahead Action" - // Add model combobox and change listener to update the settings based on slider value - - temperatureSlider.addChangeListener { - settings.temperature = temperatureSlider.value / 100.0 - } - // Update parsingModel based on modelComboBox selection - val fileChooserDescriptor = FileChooserDescriptor(true, false, false, false, false, false) - .withTitle("Select Command") - .withDescription("Choose an executable file for the auto-fix command") - addCommandButton.addActionListener { - val chosenFile = FileChooser.chooseFile(fileChooserDescriptor, project, null) - if (chosenFile != null) { - val newCommand = chosenFile.path - val confirmResult = JOptionPane.showConfirmDialog( - null, - "Add command: $newCommand?", - "Confirm Command", - JOptionPane.YES_NO_OPTION - ) - if (confirmResult == JOptionPane.YES_OPTION) { - tableModel.addRow(arrayOf(true, newCommand)) - checkboxStates.add(true) - AppSettingsState.instance.executables.add(newCommand) - } - } - } - editCommandButton.addActionListener { - val selectedRow = commandTable.selectedRow - if (selectedRow != -1) { - val currentCommand = tableModel.getValueAt(selectedRow, 1) as String - val newCommand = JOptionPane.showInputDialog( - null, - "Edit command:", - currentCommand - ) - if (newCommand != null && newCommand.isNotEmpty()) { - val confirmResult = JOptionPane.showConfirmDialog( - null, - "Update command to: $newCommand?", - "Confirm Edit", - JOptionPane.YES_NO_OPTION - ) - if (confirmResult == JOptionPane.YES_OPTION) { - tableModel.setValueAt(newCommand, selectedRow, 1) - AppSettingsState.instance.executables.remove(currentCommand) - AppSettingsState.instance.executables.add(newCommand) - } - } - } else { - JOptionPane.showMessageDialog(null, "Please select a command to edit.") - } - } - commandTable.columnModel.getColumn(0).apply { - preferredWidth = 50 - maxWidth = 100 - } - commandTable.selectionModel.addListSelectionListener { - editCommandButton.isEnabled = commandTable.selectedRow != -1 - } - editCommandButton.isEnabled = false - // Initialize task table - val values = TaskType.values() - values.forEach { taskType -> - val taskSettings = settings.getTaskSettings(taskType) - taskTableModel.addRow( - arrayOf( - taskSettings.enabled, - taskType.name, - taskSettings.model?.modelName ?: AppSettingsState.instance.smartModel, - ) - ) - } - taskTable.columnModel.getColumn(0).preferredWidth = 50 - taskTable.columnModel.getColumn(0).maxWidth = 100 - taskTable.columnModel.getColumn(1).preferredWidth = 200 - taskTable.columnModel.getColumn(2).preferredWidth = 200 - // Call setupCommandTable to initialize commandTable - setupCommandTable() - } - - override fun createCenterPanel(): JComponent { - val panel = JPanel() - panel.layout = BoxLayout(panel, BoxLayout.Y_AXIS) - panel.add(JLabel("Temperature:")) - panel.add(temperatureSlider) - panel.add(JLabel("Task Types:")) - val taskScrollPane = JBScrollPane(taskTable) - taskScrollPane.preferredSize = Dimension(350, 150) - val taskTablePanel = JPanel(BorderLayout()) - taskTablePanel.add(taskScrollPane, BorderLayout.CENTER) - panel.add(taskTablePanel) - - panel.add(autoFixCheckbox) - panel.add(allowBlockingCheckbox) - panel.add(JLabel("Auto-Fix Commands:")) - val scrollPane = JBScrollPane(commandTable) - scrollPane.preferredSize = Dimension(350, 100) - val tablePanel = JPanel(BorderLayout()) - tablePanel.add(scrollPane, BorderLayout.CENTER) - panel.add(tablePanel) - val buttonPanel = JPanel(GridLayout(1, 3)) - buttonPanel.add(addCommandButton) - buttonPanel.add(editCommandButton) - panel.add(buttonPanel) - commandTable.isEnabled = true - addCommandButton.isEnabled = true - return panel - } - - override fun doOKAction() { - // Update task settings - for (i in 0 until taskTableModel.rowCount) { - val taskType = TaskType.valueOf(taskTableModel.getValueAt(i, 1) as String) - val modelName = taskTableModel.getValueAt(i, 2) as String - val selectedModel = ChatModel.values().toList().find { it.first == modelName }?.second - settings.setTaskSettings(taskType, TaskSettings(taskTableModel.getValueAt(i, 0) as Boolean).apply { - this.model = selectedModel - }) - } - settings.autoFix = autoFixCheckbox.isSelected - settings.allowBlocking = allowBlockingCheckbox.isSelected - settings.commandAutoFixCommands = (0 until tableModel.rowCount) - .filter { tableModel.getValueAt(it, 0) as Boolean } - .map { tableModel.getValueAt(it, 1) as String } - // Update the global tool collection without removing deselected commands - settings.commandAutoFixCommands!!.forEach { command -> - if (!AppSettingsState.instance.executables.contains(command)) { - AppSettingsState.instance.executables.add(command) - } - } - super.doOKAction() - } - - private fun setupCommandTable() { - commandTable.columnModel.getColumn(0).apply { - cellEditor = DefaultCellEditor(JCheckBox()) - preferredWidth = 50 - maxWidth = 100 - } - tableModel.addTableModelListener { e -> - if (e.column == 0) { - val row = e.firstRow - val value = tableModel.getValueAt(row, 0) as Boolean - checkboxStates[row] = value - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PlanChatAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PlanChatAction.kt deleted file mode 100644 index 974a1ae8..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PlanChatAction.kt +++ /dev/null @@ -1,96 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.plan - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.actions.generic.toFile -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.apps.general.PlanChatApp -import com.simiacryptus.skyenet.apps.plan.PlanSettings -import com.simiacryptus.skyenet.apps.plan.PlanUtil.isWindows -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.file.DataStorage -import com.simiacryptus.skyenet.core.util.getModuleRootForFile -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import org.slf4j.LoggerFactory -import kotlin.collections.set - -class PlanChatAction : BaseAction() { - - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(e: AnActionEvent) { - val dialog = PlanAheadConfigDialog( - e.project, PlanSettings( - defaultModel = AppSettingsState.instance.smartModel.chatModel(), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - command = listOf( - if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" - ), - temperature = AppSettingsState.instance.temperature, - workingDir = UITools.getRoot(e), - env = mapOf(), - githubToken = AppSettingsState.instance.githubToken, - googleApiKey = AppSettingsState.instance.googleApiKey, - googleSearchEngineId = AppSettingsState.instance.googleSearchEngineId, - ) - ) - if (dialog.showAndGet()) { - // Settings are applied only if the user clicks OK - val session = Session.newGlobalID() - val folder = UITools.getSelectedFolder(e) - val root = folder?.toFile ?: getModuleRootForFile( - UITools.getSelectedFile(e)?.parent?.toFile ?: throw RuntimeException("") - ) - DataStorage.sessionPaths[session] = root - SessionProxyServer.Companion.chats[session] = PlanChatApp( - planSettings = dialog.settings.copy( - env = mapOf(), - workingDir = root.absolutePath, - language = if (isWindows) "powershell" else "bash", - command = listOf( - if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" - ), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - ), - model = AppSettingsState.instance.smartModel.chatModel(), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - showMenubar = false, - api = api, - api2 = api2, - ) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - val server = AppServer.getServer(e.project) - openBrowser(server, session.toString()) - } - } - - private fun openBrowser(server: AppServer, session: String) { - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - LoggerFactory.getLogger(PlanChatAction::class.java).warn("Error opening browser", e) - } - }.start() - } - - companion object { - private val log = LoggerFactory.getLogger(PlanChatAction::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PrePlanAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PrePlanAction.kt deleted file mode 100644 index 65c98bf1..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/plan/PrePlanAction.kt +++ /dev/null @@ -1,162 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.plan - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.actions.generic.toFile -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.openapi.ui.Messages -import com.intellij.ui.components.JBLabel -import com.intellij.ui.components.JBTextField -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.apps.general.PlanAheadApp -import com.simiacryptus.skyenet.apps.plan.PlanSettings -import com.simiacryptus.skyenet.apps.plan.PlanUtil.isWindows -import com.simiacryptus.skyenet.apps.plan.TaskBreakdownWithPrompt -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.file.DataStorage -import com.simiacryptus.skyenet.core.util.getModuleRootForFile -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.util.JsonUtil -import org.slf4j.LoggerFactory -import java.awt.GridBagConstraints -import java.awt.GridBagLayout -import javax.swing.JComponent -import javax.swing.JPanel - -class PrePlanAction : BaseAction() { - val path = "/prePlanTaskDev" - - override fun getActionUpdateThread() = ActionUpdateThread.BGT - - override fun handle(e: AnActionEvent) { - var jsonInput = Messages.showMultilineInputDialog( - e.project, - "Enter TaskBreakdownWithPrompt JSON:", - "Pre-Plan Task", - "", - Messages.getQuestionIcon(), - null, - ) ?: return - jsonInput = fillInTemplate(jsonInput) - - try { - val taskBreakdownWithPrompt = JsonUtil.fromJson(jsonInput, TaskBreakdownWithPrompt::class.java) - - val session = Session.newGlobalID() - val folder = UITools.getSelectedFolder(e) - val root = folder?.toFile ?: getModuleRootForFile( - UITools.getSelectedFile(e)?.parent?.toFile ?: throw RuntimeException("No file selected") - ) - DataStorage.sessionPaths[session] = root - - var planSettings = PlanSettings( - defaultModel = AppSettingsState.instance.smartModel.chatModel(), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - command = listOf( - if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" - ), - temperature = AppSettingsState.instance.temperature, - workingDir = UITools.getRoot(e), - env = mapOf(), - language = if (isWindows) "powershell" else "bash", - githubToken = AppSettingsState.instance.githubToken, - googleApiKey = AppSettingsState.instance.googleApiKey, - googleSearchEngineId = AppSettingsState.instance.googleSearchEngineId, - ) - planSettings = PlanAheadConfigDialog(e.project, planSettings).let { - if (!it.showAndGet()) throw RuntimeException("User cancelled") - it.settings - } - SessionProxyServer.Companion.chats[session] = PlanAheadApp( - planSettings = planSettings, - model = AppSettingsState.instance.smartModel.chatModel(), - parsingModel = AppSettingsState.instance.fastModel.chatModel(), - showMenubar = false, - initialPlan = taskBreakdownWithPrompt, - api = api, - api2 = api2, - ) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = true, - stickyInput = false, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(e.project) - openBrowser(server, session.toString()) - } catch (ex: Exception) { - Messages.showErrorDialog(e.project, "Invalid JSON input: ${ex.message}", "Error") - } - } - - private fun openBrowser(server: AppServer, session: String) { - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - companion object { - private val log = LoggerFactory.getLogger(PrePlanAction::class.java) - - fun fillInTemplate(jsonInput: String): String { - val variables = Regex("\\{\\{(\\w+)}}").findAll(jsonInput).map { it.groupValues[1] }.toSet() - if (variables.isEmpty()) return jsonInput - val formValues = showFormDialog(variables) - return variables.fold(jsonInput) { acc, variable -> - acc.replace("{{$variable}}", formValues[variable] ?: "") - } - } - - private fun showFormDialog(variables: Set): Map { - val dialog = object : DialogWrapper(true) { - val fields = variables.associateWith { JBTextField() } - - init { - init() - title = "Fill in Template Variables" - } - - override fun createCenterPanel(): JComponent { - val panel = JPanel(GridBagLayout()) - val gbc = GridBagConstraints().apply { - fill = GridBagConstraints.HORIZONTAL - weightx = 1.0 - } - variables.forEach { variable -> - gbc.gridy++ - gbc.gridx = 0 - panel.add(JBLabel(variable), gbc) - gbc.gridx = 1 - panel.add(fields[variable], gbc) - } - return panel - } - - fun getValues(): Map { - return fields.mapValues { (_, field) -> field.text } - } - } - return if (dialog.showAndGet()) { - dialog.getValues() - } else { - mapOf() - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/problems/AnalyzeProblemAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/problems/AnalyzeProblemAction.kt deleted file mode 100644 index 52fdbd52..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/problems/AnalyzeProblemAction.kt +++ /dev/null @@ -1,255 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.problems - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.actions.generic.toFile -import com.github.simiacryptus.aicoder.actions.test.TestResultAutofixAction.Companion.findGitRoot -import com.github.simiacryptus.aicoder.actions.test.TestResultAutofixAction.Companion.getProjectStructure -import com.github.simiacryptus.aicoder.actions.test.TestResultAutofixAction.Companion.tripleTilde -import com.github.simiacryptus.aicoder.actions.test.TestResultAutofixAction.ParsedError -import com.github.simiacryptus.aicoder.actions.test.TestResultAutofixAction.ParsedErrors -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.IdeaChatClient -import com.intellij.analysis.problemsView.toolWindow.ProblemNode -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.intellij.openapi.project.Project -import com.intellij.openapi.util.TextRange -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.PsiManager -import com.simiacryptus.diff.addApplyFileDiffLinks -import com.simiacryptus.jopenai.API -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.AgentPatterns -import com.simiacryptus.skyenet.Retryable -import com.simiacryptus.skyenet.core.actors.ParsedActor -import com.simiacryptus.skyenet.core.actors.SimpleActor -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager -import com.simiacryptus.skyenet.webui.session.SessionTask -import com.simiacryptus.skyenet.webui.session.SocketManager -import com.simiacryptus.util.JsonUtil -import javax.swing.JOptionPane - -class AnalyzeProblemAction : AnAction() { - companion object { - private val log = Logger.getInstance(AnalyzeProblemAction::class.java) - } - - override fun actionPerformed(e: AnActionEvent) { - val project: Project = e.project ?: return - val item = e.getData(PlatformDataKeys.SELECTED_ITEM) as ProblemNode? ?: return - val file: VirtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return - val gitRoot = findGitRoot(file) - - Thread { - try { - val problemInfo = buildString { - appendLine("File: ${file.path}") - appendLine("Problem: ${item.text}") - - val psiFile = PsiManager.getInstance(project).findFile(file) - val fileType = if (psiFile != null) { - val fileType = psiFile.fileType.name - appendLine("File type: $fileType") - fileType - } else { - "" - } - - val document = FileDocumentManager.getInstance().getDocument(file) - if (document != null) { - val lineNumber = item.line - val column = item.column - appendLine("Position: Line ${lineNumber + 1}, Column ${column + 1}") - - // Capture 5 lines of context - val startLine = maxOf(0, lineNumber - 2) - val endLine = minOf(document.lineCount - 1, lineNumber + 2) - val contextLines = (startLine..endLine).map { line -> - val start = document.getLineStartOffset(line) - val end = document.getLineEndOffset(line) - document.getText(TextRange(start, end)) - } - appendLine("Context:") - contextLines.forEachIndexed { index, content -> - val linePrefix = if (index + startLine == lineNumber) ">" else " " - appendLine("$linePrefix ${index + startLine + 1}: $content") - } - appendLine("${" ".repeat(column + 5)}^") - } - - val projectStructure = getProjectStructure(gitRoot) - appendLine("Project structure:\n ${projectStructure.replace("\n", "\n ")}\n") - appendLine("## ${file.path}\n```${fileType.lowercase()}\n${document?.text}\n```\n") - } - log.info("Problem info: $problemInfo") - openAnalysisSession(project, problemInfo, gitRoot) - } catch (ex: Throwable) { - log.error("Error analyzing problem", ex) - JOptionPane.showMessageDialog(null, ex.message, "Error", JOptionPane.ERROR_MESSAGE) - } - }.start() - - } - - private fun openAnalysisSession(project: Project, problemInfo: String, gitRoot: VirtualFile?) { - val session = Session.newGlobalID() - SessionProxyServer.chats[session] = ProblemAnalysisApp(session, problemInfo, gitRoot) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - override fun update(e: AnActionEvent) { - val project = e.project - val file = e.getData(CommonDataKeys.VIRTUAL_FILE) - e.presentation.isEnabledAndVisible = project != null && file != null - } - - inner class ProblemAnalysisApp( - val session: Session, - val problemInfo: String, - val gitRoot: VirtualFile? - ) : ApplicationServer( - applicationName = "Problem Analysis", - path = "/analyzeProblem", - showMenubar = false, - ) { - override val singleInput = true - override val stickyInput = false - - override fun newSession(user: User?, session: Session): SocketManager { - val socketManager = super.newSession(user, session) - val ui = (socketManager as ApplicationSocketManager).applicationInterface - val task = ui.newTask() - task.add("Analyzing problem and suggesting fixes...") - Thread { - analyzeProblem(ui, task, api = IdeaChatClient.instance) - }.start() - return socketManager - } - - private fun analyzeProblem(ui: ApplicationInterface, task: SessionTask, api: API) { - try { - Retryable(ui, task) { - val plan = ParsedActor( - resultClass = ParsedErrors::class.java, - prompt = """ - You are a helpful AI that helps people with coding. - Given the response of a test failure, identify one or more distinct errors. - For each error: - 1) predict the files that need to be fixed - 2) predict related files that may be needed to debug the issue - """.trimIndent(), - model = AppSettingsState.instance.smartModel.chatModel() - ).answer(listOf(problemInfo), api = IdeaChatClient.instance) - - task.add( - AgentPatterns.displayMapInTabs( - mapOf( - "Text" to renderMarkdown(plan.text, ui = ui), - "JSON" to renderMarkdown( - "${tripleTilde}json\n${JsonUtil.toJson(plan.obj)}\n$tripleTilde", - ui = ui - ), - ) - ) - ) - - plan.obj.errors?.forEach { error -> - Retryable(ui, task) { - val filesToFix = (error.fixFiles ?: emptyList()) + (error.relatedFiles ?: emptyList()) - val summary = filesToFix.joinToString("\n\n") { filePath -> - val file = gitRoot?.toFile?.resolve(filePath) - if (file?.exists() == true) { - """ - # $filePath - $tripleTilde${filePath.split('.').lastOrNull()} - ${file.readText()} - $tripleTilde - """.trimIndent() - } else { - "# $filePath\nFile not found" - } - } - - generateAndAddResponse(ui, task, error, summary, filesToFix, api) - } - } - "" - } - } catch (e: Exception) { - task.error(ui, e) - } - } - - private fun generateAndAddResponse( - ui: ApplicationInterface, - task: SessionTask, - error: ParsedError, - summary: String, - filesToFix: List, - api: API - ): String { - val response = SimpleActor( - prompt = """ - |You are a helpful AI that helps people with coding. - |Suggest fixes for the following problem: - |$problemInfo - - |Here are the relevant files: - |$summary - - |Response should use one or more code patches in diff format within ${tripleTilde}diff code blocks. - |Each diff should be preceded by a header that identifies the file being modified. - |The diff format should use + for line additions, - for line deletions. - |The diff should include 2 lines of context before and after every change. - """.trimMargin(), - model = AppSettingsState.instance.smartModel.chatModel() - ).answer(listOf(error.message ?: ""), api = IdeaChatClient.instance) - - var markdown = ui.socketManager?.addApplyFileDiffLinks( - root = root.toPath(), - response = response, - handle = { newCodeMap -> - newCodeMap.forEach { (path, newCode) -> - task.complete("$path Updated") - } - }, - ui = ui, - api = api, - ) - val msg = "
${renderMarkdown(markdown!!)}
" - return msg - } - - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/test/TestResultAutofixAction.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/actions/test/TestResultAutofixAction.kt deleted file mode 100644 index b1e10b9e..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/actions/test/TestResultAutofixAction.kt +++ /dev/null @@ -1,315 +0,0 @@ -package com.github.simiacryptus.aicoder.actions.test - -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.BaseAction -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.github.simiacryptus.aicoder.util.IdeaChatClient -import com.intellij.execution.testframework.AbstractTestProxy -import com.intellij.execution.testframework.sm.runner.SMTestProxy -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.vfs.VirtualFile -import com.simiacryptus.diff.FileValidationUtils -import com.simiacryptus.diff.FileValidationUtils.Companion.isGitignore -import com.simiacryptus.diff.addApplyFileDiffLinks -import com.simiacryptus.jopenai.models.chatModel -import com.simiacryptus.skyenet.AgentPatterns -import com.simiacryptus.skyenet.Retryable -import com.simiacryptus.skyenet.core.actors.ParsedActor -import com.simiacryptus.skyenet.core.actors.SimpleActor -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown -import com.simiacryptus.skyenet.webui.application.AppInfoData -import com.simiacryptus.skyenet.webui.application.ApplicationInterface -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.application.ApplicationSocketManager -import com.simiacryptus.skyenet.webui.session.SessionTask -import com.simiacryptus.skyenet.webui.session.SocketManager -import com.simiacryptus.util.JsonUtil -import org.jetbrains.annotations.NotNull -import java.io.File -import java.nio.file.Path -import javax.swing.JOptionPane - -class TestResultAutofixAction : BaseAction() { - companion object { - private val log = Logger.getInstance(TestResultAutofixAction::class.java) - val tripleTilde = "`" + "``" // This is a workaround for the markdown parser when editing this file - - fun getFiles( - virtualFiles: Array? - ): MutableSet { - val codeFiles = mutableSetOf() // Set to avoid duplicates - virtualFiles?.forEach { file -> - if (file.name.startsWith(".")) return@forEach - if (isGitignore(file.toNioPath())) return@forEach - if (file.isDirectory) { - codeFiles.addAll(getFiles(file.children)) - } else { - codeFiles.add((file.toNioPath())) - } - } - return codeFiles - } - - fun getFiles( - virtualFiles: Array? - ): MutableSet { - val codeFiles = mutableSetOf() // Set to avoid duplicates - virtualFiles?.forEach { file -> - if (file.fileName.startsWith(".")) return@forEach - if (isGitignore(file)) return@forEach - if (file.toFile().isDirectory) { - codeFiles.addAll(getFiles(file.toFile().listFiles().map { it.toPath() }.toTypedArray())) - } else { - codeFiles.add(file) - } - } - return codeFiles - } - - fun getProjectStructure(projectPath: VirtualFile?): String { - return getProjectStructure(Path.of((projectPath ?: return "Project path is null").path)) - } - - fun getProjectStructure(root: Path): String { - val codeFiles = getFiles(arrayOf(root)) - .filter { it.toFile().length() < 1024 * 1024 / 2 } // Limit to 0.5MB - .map { root.relativize(it) ?: it }.toSet() - val str = codeFiles - .asSequence() - .filter { root.resolve(it)?.toFile()?.exists() == true } - .distinct().sorted() - .joinToString("\n") { path -> - "* ${path} - ${root.resolve(path)?.toFile()?.length() ?: "?"} bytes".trim() - } - return str - } - - fun findGitRoot(path: Path?): Path? { - var current: Path? = path - while (current != null) { - if (current.resolve(".git").toFile().exists()) { - return current - } - current = current.parent - } - return null - } - - fun findGitRoot(virtualFile: VirtualFile?): VirtualFile? { - var current: VirtualFile? = virtualFile - while (current != null) { - if (current.findChild(".git") != null) { - return current - } - current = current.parent - } - return null - } - } - - override fun handle(e: AnActionEvent) { - val testProxy = e.getData(AbstractTestProxy.DATA_KEY) as? SMTestProxy ?: return - val dataContext = e.dataContext - val virtualFile = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext)?.firstOrNull() - val root = Companion.findGitRoot(virtualFile) - Thread { - try { - val testInfo = getTestInfo(testProxy) - val projectStructure = getProjectStructure(root) - openAutofixWithTestResult(e, testInfo, projectStructure) - } catch (ex: Throwable) { - log.error("Error analyzing test result", ex) - JOptionPane.showMessageDialog(null, ex.message, "Error", JOptionPane.ERROR_MESSAGE) - } - }.start() - } - - override fun isEnabled(@NotNull e: AnActionEvent): Boolean { - val testProxy = e.getData(AbstractTestProxy.DATA_KEY) - return testProxy != null - } - - private fun getTestInfo(testProxy: SMTestProxy): String { - val sb = StringBuilder() - sb.appendLine("Test Name: ${testProxy.name}") - sb.appendLine("Duration: ${testProxy.duration} ms") - - if (testProxy.errorMessage != null) { - sb.appendLine("Error Message:") - sb.appendLine(testProxy.errorMessage) - } - - if (testProxy.stacktrace != null) { - sb.appendLine("Stacktrace:") - sb.appendLine(testProxy.stacktrace) - } - - return sb.toString() - } - - private fun openAutofixWithTestResult(e: AnActionEvent, testInfo: String, projectStructure: String) { - val session = Session.newGlobalID() - SessionProxyServer.chats[session] = TestResultAutofixApp(session, testInfo, e.project?.basePath, projectStructure) - ApplicationServer.appInfoMap[session] = AppInfoData( - applicationName = "Code Chat", - singleInput = false, - stickyInput = true, - loadImages = false, - showMenubar = false - ) - - val server = AppServer.getServer(e.project) - - Thread { - Thread.sleep(500) - try { - val uri = server.server.uri.resolve("/#$session") - log.info("Opening browser to $uri") - browse(uri) - } catch (e: Throwable) { - log.warn("Error opening browser", e) - } - }.start() - } - - inner class TestResultAutofixApp( - val session: Session, - val testInfo: String, - val projectPath: String?, - val projectStructure: String - ) : ApplicationServer( - applicationName = "Test Result Autofix", - path = "/fixTest", - showMenubar = false, - ) { - override val singleInput = true - override val stickyInput = false - override fun newSession(user: User?, session: Session): SocketManager { - val socketManager = super.newSession(user, session) - val ui = (socketManager as ApplicationSocketManager).applicationInterface - val task = ui.newTask() - task.add("Analyzing test result and suggesting fixes...") - Thread { - runAutofix(ui, task) - }.start() - return socketManager - } - - private fun runAutofix(ui: ApplicationInterface, task: SessionTask) { - try { - Retryable(ui, task) { - val plan = ParsedActor( - resultClass = ParsedErrors::class.java, - prompt = """ - You are a helpful AI that helps people with coding. - Given the response of a test failure, identify one or more distinct errors. - For each error: - 1) predict the files that need to be fixed - 2) predict related files that may be needed to debug the issue - - Project structure: - $projectStructure - 1) predict the files that need to be fixed - 2) predict related files that may be needed to debug the issue - """.trimIndent(), - model = AppSettingsState.instance.smartModel.chatModel() - ).answer(listOf(testInfo), api = IdeaChatClient.instance) - - task.add( - AgentPatterns.displayMapInTabs( - mapOf( - "Text" to renderMarkdown(plan.text, ui = ui), - "JSON" to renderMarkdown( - "${tripleTilde}json\n${JsonUtil.toJson(plan.obj)}\n$tripleTilde", - ui = ui - ), - ) - ) - ) - - plan.obj.errors?.forEach { error -> - Retryable(ui, task) { - val filesToFix = (error.fixFiles ?: emptyList()) + (error.relatedFiles ?: emptyList()) - val summary = filesToFix.joinToString("\n\n") { filePath -> - val file = File(projectPath, filePath) - if (file.exists()) { - """ - # $filePath - $tripleTilde${filePath.split('.').lastOrNull()} - ${file.readText()} - $tripleTilde - """.trimIndent() - } else { - "# $filePath\nFile not found" - } - } - - generateAndAddResponse(ui, task, error, summary, filesToFix) - } - } - "" - } - } catch (e: Exception) { - task.error(ui, e) - } - } - - private fun generateAndAddResponse( - ui: ApplicationInterface, - task: SessionTask, - error: ParsedError, - summary: String, - filesToFix: List - ): String { - val response = SimpleActor( - prompt = """ - You are a helpful AI that helps people with coding. - Suggest fixes for the following test failure: - $testInfo - - Here are the relevant files: - $summary - -Project structure: -$projectStructure - - Response should use one or more code patches in diff format within ${tripleTilde}diff code blocks. - Each diff should be preceded by a header that identifies the file being modified. - The diff format should use + for line additions, - for line deletions. - The diff should include 2 lines of context before and after every change. - """.trimIndent(), - model = AppSettingsState.instance.smartModel.chatModel() - ).answer(listOf(error.message ?: ""), api = IdeaChatClient.instance) - - var markdown = ui.socketManager?.addApplyFileDiffLinks( - root = root.toPath(), - response = response, - handle = { newCodeMap -> - newCodeMap.forEach { (path, newCode) -> - task.complete("$path Updated") - } - }, - ui = ui, - api = api, - ) - val msg = "
${renderMarkdown(markdown!!)}
" - return msg - } - } - - data class ParsedErrors( - val errors: List? = null - ) - - data class ParsedError( - val message: String? = null, - val relatedFiles: List? = null, - val fixFiles: List? = null - ) -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsComponent.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsComponent.kt deleted file mode 100644 index 84889dd4..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsComponent.kt +++ /dev/null @@ -1,416 +0,0 @@ -package com.github.simiacryptus.aicoder.config - - -import com.github.simiacryptus.aicoder.actions.plan.PlanAheadConfigDialog.Companion.isVisible -import com.github.simiacryptus.aicoder.util.IdeaChatClient -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileChooser.FileChooser -import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.fileEditor.OpenFileDescriptor -import com.intellij.openapi.project.Project -import com.intellij.openapi.project.ProjectManager -import com.intellij.openapi.ui.ComboBox -import com.intellij.openapi.vfs.LocalFileSystem -import com.intellij.ui.SimpleListCellRenderer -import com.intellij.ui.components.JBCheckBox -import com.intellij.ui.components.JBList -import com.intellij.ui.components.JBTextField -import com.intellij.ui.table.JBTable -import com.simiacryptus.jopenai.models.APIProvider -import com.simiacryptus.jopenai.models.ChatModel -import com.simiacryptus.jopenai.models.ImageModels -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import com.simiacryptus.skyenet.core.platform.AwsPlatform -import java.awt.BorderLayout -import java.awt.Dimension -import java.awt.event.ActionEvent -import java.io.FileOutputStream -import javax.swing.* -import javax.swing.event.ListSelectionEvent -import javax.swing.event.ListSelectionListener -import javax.swing.table.DefaultTableCellRenderer -import javax.swing.table.DefaultTableModel - -class AppSettingsComponent : com.intellij.openapi.Disposable { - @Suppress("unused") - @Name("GitHub Token") - val githubToken = JBTextField().apply { - toolTipText = "GitHub Personal Access Token" - columns = 30 - } - @Suppress("unused") - @Name("Google API Key") - val googleApiKey = JBTextField().apply { - toolTipText = "Google API Key" - columns = 30 - } - @Suppress("unused") - @Name("Google Search Engine ID") - val googleSearchEngineId = JBTextField().apply { - toolTipText = "Google Search Engine ID" - columns = 30 - } - @Suppress("unused") - @Name("AWS Profile") - val awsProfile = JBTextField().apply { - toolTipText = "AWS Profile" - columns = 30 - } - @Suppress("unused") - @Name("AWS Region") - val awsRegion = JBTextField().apply { - toolTipText = "AWS Region" - columns = 30 - } - @Suppress("unused") - @Name("AWS Bucket") - val awsBucket = JBTextField().apply { - toolTipText = "AWS Bucket" - columns = 30 - } - @Suppress("unused") - @Name("Store Metadata") - val storeMetadata = JTextArea().apply { - lineWrap = true - wrapStyleWord = true - } - - val executablesModel = DefaultListModel().apply { - AppSettingsState.instance.executables.forEach { addElement(it) } - } - val executablesList = JBList(executablesModel) - - @Suppress("unused") - @Name("Executables") - val executablesPanel = JPanel(BorderLayout()).apply { - val scrollPane = JScrollPane(executablesList) - scrollPane.preferredSize = Dimension(300, 200) - add(scrollPane, BorderLayout.CENTER) - val buttonPanel = JPanel() - val addButton = JButton("Add") - val removeButton = JButton("Remove") - val editButton = JButton("Edit") - removeButton.isEnabled = false - editButton.isEnabled = false - - addButton.addActionListener { - val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor() - descriptor.title = "Select Executable" - FileChooser.chooseFile(descriptor, null, null) { file -> - val executablePath = file.path - if (executablePath.isNotBlank() && !executablesModel.contains(executablePath)) { - executablesModel.addElement(executablePath) - AppSettingsState.instance.executables.add(executablePath) - } - } - } - removeButton.addActionListener { - val selectedIndices = executablesList.selectedIndices - for (i in selectedIndices.reversed()) { - val removed = executablesModel.remove(i) - AppSettingsState.instance.executables.remove(removed) - } - } - editButton.addActionListener { - val selectedIndex = executablesList.selectedIndex - if (selectedIndex != -1) { - val currentValue = executablesModel.get(selectedIndex) - val newValue = JOptionPane.showInputDialog(this, "Edit executable path:", currentValue) - if (newValue != null && newValue.isNotBlank()) { - executablesModel.set(selectedIndex, newValue) - AppSettingsState.instance.executables.remove(currentValue) - AppSettingsState.instance.executables.add(newValue) - } - } - } - executablesList.addListSelectionListener(object : ListSelectionListener { - override fun valueChanged(e: ListSelectionEvent?) { - val hasSelection = executablesList.selectedIndex != -1 - removeButton.isEnabled = hasSelection - editButton.isEnabled = hasSelection - } - }) - buttonPanel.add(addButton) - buttonPanel.add(removeButton) - buttonPanel.add(editButton) - add(buttonPanel, BorderLayout.SOUTH) - // Enable multiple selection for the list - executablesList.selectionMode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION - } - - @Suppress("unused") - @Name("Human Language") - val humanLanguage = JBTextField() - - @Suppress("unused") - @Name("Listening Port") - val listeningPort = JBTextField() - - @Suppress("unused") - @Name("Listening Endpoint") - val listeningEndpoint = JBTextField() - - @Suppress("unused") - @Name("Suppress Errors") - val suppressErrors = JBCheckBox() - - @Suppress("unused") - @Name("Model") - val smartModel = ComboBox() - - @Suppress("unused") - @Name("Model") - val fastModel = ComboBox() - - @Suppress("unused") - @Name("Main Image Model") - val mainImageModel = ComboBox() - - @Suppress("unused") - @Name("Enable API Log") - val apiLog = JBCheckBox() - - @Suppress("unused") - val openApiLog = JButton(object : AbstractAction("Open API Log") { - override fun actionPerformed(e: ActionEvent) { - AppSettingsState.auxiliaryLog?.let { - if (it.exists()) { - val project = ApplicationManager.getApplication().runReadAction { - ProjectManager.getInstance().openProjects.firstOrNull() - } - ApplicationManager.getApplication().invokeLater { - val virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(it) - val openFileDescriptor = OpenFileDescriptor(project, virtualFile!!, virtualFile.length.toInt()) - FileEditorManager.getInstance(project!!) - .openTextEditor(openFileDescriptor, true)?.document?.setReadOnly( - true - ) - } - } - } - } - }) - - - @Suppress("unused") - val clearApiLog = JButton(object : AbstractAction("Clear API Log") { - override fun actionPerformed(e: ActionEvent) { - val openAIClient = IdeaChatClient.instance - openAIClient.logStreams.retainAll { it.close(); false } - AppSettingsState.auxiliaryLog?.let { - if (it.exists()) { - it.delete() - } - openAIClient.logStreams.add(FileOutputStream(it, true).buffered()) - } - } - }) - - - @Suppress("unused") - @Name("Developer Tools") - val devActions = JBCheckBox() - - @Suppress("unused") - @Name("Edit API Requests") - val editRequests = JBCheckBox() - - @Suppress("unused") - @Name("Disable Auto-Open URLs") - val disableAutoOpenUrls = JBCheckBox() - - - @Suppress("unused") - @Name("Plugin Home") - val pluginHome = JBTextField() - - @Suppress("unused") - val choosePluginHome = com.intellij.openapi.ui.TextFieldWithBrowseButton(pluginHome).apply { - addBrowseFolderListener( - "Select Plugin Home Directory", - null, - null, - FileChooserDescriptorFactory.createSingleFolderDescriptor() - ) - } - - @Suppress("unused") - @Name("Shell Command") - val shellCommand = JBTextField() - - @Suppress("unused") - @Name("Show Welcome Screen") - val showWelcomeScreen = JBCheckBox("Show Welcome Screen", true) - - @Suppress("unused") - @Name("Enable Legacy Actions") - val enableLegacyActions = JBCheckBox() - - @Suppress("unused") - @Name("Temperature") - val temperature = JBTextField() - - @Name("APIs") - val apis = JBTable(DefaultTableModel(arrayOf("Provider", "Key", "Base URL"), 0)).apply { - columnModel.getColumn(0).preferredWidth = 100 - columnModel.getColumn(1).preferredWidth = 200 - columnModel.getColumn(2).preferredWidth = 200 - val keyColumnIndex = 1 - columnModel.getColumn(keyColumnIndex).cellRenderer = object : DefaultTableCellRenderer() { - override fun setValue(value: Any?) { - text = - if (value is String && value.isNotEmpty()) value.map { '*' }.joinToString("") else value?.toString() - ?: "" - } - } - } - - @Name("User-Supplied Models") - val userSuppliedModels = JBTable(DefaultTableModel(arrayOf("Display Name", "Model ID", "Provider"), 0)).apply { - columnModel.getColumn(0).preferredWidth = 150 - columnModel.getColumn(1).preferredWidth = 200 - columnModel.getColumn(2).preferredWidth = 100 - columnModel.getColumn(2).cellEditor = DefaultCellEditor(JComboBox(APIProvider.values().map { it.name }.toTypedArray())) - } - val addUserModelButton = JButton("Add Model").apply { - addActionListener { - (userSuppliedModels.model as DefaultTableModel).addRow(arrayOf("", "", APIProvider.OpenAI)) - } - } - val removeUserModelButton = JButton("Remove Model").apply { - addActionListener { - if (userSuppliedModels.selectedRow != -1) - (userSuppliedModels.model as DefaultTableModel).removeRow(userSuppliedModels.selectedRow) - } - } - - - @Name("Editor Actions") - var usage = UsageTable(ApplicationServices.usageManager) - fun getUserSuppliedModels(): List { - return (0 until userSuppliedModels.rowCount).map { row -> - AppSettingsState.UserSuppliedModel( - userSuppliedModels.getValueAt(row, 0) as String, - userSuppliedModels.getValueAt(row, 1) as String, - userSuppliedModels.getValueAt(row, 2) as APIProvider - ) - } - } - - fun setUserSuppliedModels(models: List) { - val model = userSuppliedModels.model as DefaultTableModel - model.rowCount = 0 - models.forEach { model.addRow(arrayOf(it.displayName, it.modelId, it.provider)) } - } - - init { - // Initialize new fields - githubToken.text = AppSettingsState.instance.githubToken ?: "" - googleApiKey.text = AppSettingsState.instance.googleApiKey ?: "" - googleSearchEngineId.text = AppSettingsState.instance.googleSearchEngineId ?: "" - awsProfile.text = AppSettingsState.instance.awsProfile ?: "" - awsRegion.text = AppSettingsState.instance.awsRegion ?: "" - awsBucket.text = AppSettingsState.instance.awsBucket ?: "" - // Initialize executables list - setExecutables(AppSettingsState.instance.executables) - fun getExecutables(): Set { - fun setExecutables(executables: Set) { - val model = - ((executablesPanel.getComponent(0) as? JScrollPane)?.viewport?.view as? JList)?.model as? DefaultListModel - model?.clear() - executables.forEach { model?.addElement(it) } - } - - val model = - ((executablesPanel.getComponent(0) as? JScrollPane)?.viewport?.view as? JList)?.model as? DefaultListModel - return model?.elements()?.toList()?.toSet() ?: emptySet() - } - ChatModel.values() - .filter { - AppSettingsState.instance.apiKey?.filter { it.value.isNotBlank() }?.keys?.contains(it.value.provider.name) - ?: false - } - .forEach { - this.smartModel.addItem(it.value.modelName) - this.fastModel.addItem(it.value.modelName) - } - ImageModels.values().forEach { - this.mainImageModel.addItem(it.name) - } - // Sort the items in the ComboBoxes - val smartModelItems = (0 until smartModel.itemCount).map { smartModel.getItemAt(it) } - .filter { modelItem -> - isVisible(ChatModel.values().entries.find { it.value.modelName == modelItem }?.value ?: return@filter false) - } - .sortedBy { modelItem -> - val model = - ChatModel.values().entries.find { it.value.modelName == modelItem }?.value ?: return@sortedBy "" - "${model.provider.name} - ${model.modelName}" - }.toList() - val fastModelItems = (0 until fastModel.itemCount).map { fastModel.getItemAt(it) } - .filter { modelItem -> - isVisible(ChatModel.values().entries.find { it.value.modelName == modelItem }?.value ?: return@filter false) - } - .sortedBy { modelItem -> - val model = - ChatModel.values().entries.find { it.value.modelName == modelItem }?.value ?: return@sortedBy "" - "${model.provider.name} - ${model.modelName}" - }.toList() - smartModel.removeAllItems() - fastModel.removeAllItems() - smartModelItems.forEach { smartModel.addItem(it) } - fastModelItems.forEach { fastModel.addItem(it) } - this.smartModel.isEditable = true - this.fastModel.isEditable = true - this.smartModel.renderer = getModelRenderer() - this.fastModel.renderer = getModelRenderer() - this.mainImageModel.isEditable = true - this.mainImageModel.renderer = getImageModelRenderer() - } - - - override fun dispose() { - } - - private fun getModelRenderer(): ListCellRenderer = object : SimpleListCellRenderer() { - override fun customize( - list: JList, - value: String?, - index: Int, - selected: Boolean, - hasFocus: Boolean - ) { - text = value // Here you can add more customization if needed - if (value != null) { - val model = ChatModel.values().entries.find { it.value.modelName == value }?.value - text = "${model?.provider?.name} - $value" - } - } - } - - private fun getImageModelRenderer(): ListCellRenderer = object : SimpleListCellRenderer() { - override fun customize( - list: JList, - value: String?, - index: Int, - selected: Boolean, - hasFocus: Boolean - ) { - text = value // Here you can add more customization if needed - } - } - - fun getExecutables(): Set { - val model = - ((executablesPanel.getComponent(0) as? JScrollPane)?.viewport?.view as? JList)?.model as? DefaultListModel - return model?.elements()?.toList()?.toSet() ?: emptySet() - } - - fun setExecutables(executables: Set) { - val model = - ((executablesPanel.getComponent(0) as? JScrollPane)?.viewport?.view as? JList)?.model as? DefaultListModel - model?.clear() - executables.forEach { model?.addElement(it) } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsConfigurable.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsConfigurable.kt deleted file mode 100644 index b6e1f160..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsConfigurable.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.github.simiacryptus.aicoder.config - -import com.github.simiacryptus.aicoder.util.UITools - -open class AppSettingsConfigurable : UIAdapter(AppSettingsState.instance) { - override fun read(component: AppSettingsComponent, settings: AppSettingsState) { - UITools.readKotlinUIViaReflection(component, settings) - } - - override fun write(settings: AppSettingsState, component: AppSettingsComponent) { - UITools.writeKotlinUIViaReflection(settings, component) - } - - override fun getPreferredFocusedComponent() = component?.temperature - - override fun newComponent() = AppSettingsComponent() - - override fun newSettings() = AppSettingsState() -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsState.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsState.kt deleted file mode 100644 index f342c04f..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/AppSettingsState.kt +++ /dev/null @@ -1,201 +0,0 @@ -package com.github.simiacryptus.aicoder.config - -/** - * Stores and manages plugin configuration settings. - * - * This class is responsible for persisting and retrieving the plugin's - * configuration settings. It uses the IntelliJ Platform's persistence - * framework to save settings across IDE restarts. - */ -import com.fasterxml.jackson.annotation.JsonIgnore -import com.github.simiacryptus.aicoder.util.PluginStartupActivity.Companion.addUserSuppliedModels -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.components.PersistentStateComponent -import com.intellij.openapi.components.State -import com.intellij.openapi.components.Storage -import com.intellij.openapi.util.io.FileUtil -import com.intellij.util.xmlb.XmlSerializerUtil -import com.simiacryptus.jopenai.models.APIProvider -import com.simiacryptus.jopenai.models.ImageModels -import com.simiacryptus.jopenai.models.OpenAIModels -import com.simiacryptus.skyenet.core.platform.AwsPlatform -import com.simiacryptus.util.JsonUtil -import org.slf4j.LoggerFactory -import java.io.File - -@State(name = "org.intellij.sdk.settings.AppSettingsState", storages = [Storage("SdkSettingsPlugin.xml")]) -data class AppSettingsState( - var temperature: Double = 0.1, - var smartModel: String = OpenAIModels.GPT4o.modelName, - var fastModel: String = OpenAIModels.GPT4oMini.modelName, - var mainImageModel: String = ImageModels.DallE3.modelName, - var listeningPort: Int = 8081, - var listeningEndpoint: String = "localhost", - var humanLanguage: String = "English", - var apiThreads: Int = 4, - var apiBase: Map? = mapOf("OpenAI" to "https://api.openai.com/v1"), - var apiKey: Map? = mapOf("OpenAI" to ""), - var modalTasks: Boolean = false, - var suppressErrors: Boolean = false, - var apiLog: Boolean = false, - var devActions: Boolean = false, - var editRequests: Boolean = false, - var disableAutoOpenUrls: Boolean = false, - var storeMetadata: String? = null, - var pluginHome: File = run { - var logPath = System.getProperty("idea.plugins.path") - if (logPath == null) { - logPath = System.getProperty("java.io.tmpdir") - } - if (logPath == null) { - logPath = System.getProperty("user.home") - } - File(logPath, "AICodingAsst") - }, - var showWelcomeScreen: Boolean = true, - var greetedVersion: String = "", - var shellCommand: String = getDefaultShell(), - var enableLegacyActions: Boolean = false, - var executables: MutableSet = mutableSetOf(), - var recentArguments: MutableList = mutableListOf(), - val recentCommands: MutableMap = mutableMapOf(), - var userSuppliedModels: MutableList = mutableListOf(), - var githubToken: String? = null, - var googleApiKey: String? = null, - var googleSearchEngineId: String? = null, - var awsProfile: String? = null, - var awsRegion: String? = null, - var awsBucket: String? = null -) : PersistentStateComponent { - private var onSettingsLoadedListeners = mutableListOf<() -> Unit>() - - @JsonIgnore - override fun getState(): SimpleEnvelope { - val value = JsonUtil.toJson(this) - return SimpleEnvelope(value) - } - - fun getRecentCommands(id: String) = recentCommands.computeIfAbsent(id) { MRUItems() } - - override fun loadState(state: SimpleEnvelope) { - state.value ?: return - val fromJson = try { - JsonUtil.fromJson(state.value!!, AppSettingsState::class.java) - } catch (e: Exception) { - log.warn("Error loading settings: ${state.value}", e) - AppSettingsState() - } - XmlSerializerUtil.copyBean(fromJson, this) - addUserSuppliedModels(fromJson.userSuppliedModels) - recentCommands.clear() - recentCommands.putAll(fromJson.recentCommands) - notifySettingsLoaded() - } - - fun addOnSettingsLoadedListener(listener: () -> Unit) { - onSettingsLoadedListeners.add(listener) - } - - private fun notifySettingsLoaded() { - onSettingsLoadedListeners.forEach { it() } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - other as AppSettingsState - if (temperature != other.temperature) return false - if (smartModel != other.smartModel) return false - if (fastModel != other.fastModel) return false - if (mainImageModel != other.mainImageModel) return false - if (listeningPort != other.listeningPort) return false - if (listeningEndpoint != other.listeningEndpoint) return false - if (humanLanguage != other.humanLanguage) return false - if (apiThreads != other.apiThreads) return false - if (apiBase != other.apiBase) return false - if (apiKey != other.apiKey) return false - if (modalTasks != other.modalTasks) return false - if (suppressErrors != other.suppressErrors) return false - if (apiLog != other.apiLog) return false - if (devActions != other.devActions) return false - if (editRequests != other.editRequests) return false - if (storeMetadata != other.storeMetadata) return false - if (FileUtil.filesEqual(pluginHome, other.pluginHome)) return false - if (recentCommands != other.recentCommands) return false - if (showWelcomeScreen != other.showWelcomeScreen) return false - if (greetedVersion != other.greetedVersion) return false - if (mainImageModel != other.mainImageModel) return false - if (enableLegacyActions != other.enableLegacyActions) return false - if (executables != other.executables) return false - //userSuppliedModels - if (userSuppliedModels.toTypedArray().contentDeepEquals(other.userSuppliedModels.toTypedArray()).not()) return false - if (googleApiKey != other.googleApiKey) return false - if (googleSearchEngineId != other.googleSearchEngineId) return false - if (githubToken != other.githubToken) return false - if (awsProfile != other.awsProfile) return false - if (awsRegion != other.awsRegion) return false - if (awsBucket != other.awsBucket) return false - return true - } - - override fun hashCode(): Int { - var result = temperature.hashCode() - result = 31 * result + smartModel.hashCode() - result = 31 * result + fastModel.hashCode() - result = 31 * result + enableLegacyActions.hashCode() - result = 31 * result + mainImageModel.hashCode() - result = 31 * result + listeningPort - result = 31 * result + listeningEndpoint.hashCode() - result = 31 * result + humanLanguage.hashCode() - result = 31 * result + apiThreads - result = 31 * result + (apiBase?.hashCode() ?: 0) - result = 31 * result + (apiKey?.hashCode() ?: 0) - result = 31 * result + modalTasks.hashCode() - result = 31 * result + suppressErrors.hashCode() - result = 31 * result + apiLog.hashCode() - result = 31 * result + devActions.hashCode() - result = 31 * result + editRequests.hashCode() - result = 31 * result + (storeMetadata?.hashCode() ?: 0) - result = 31 * result + FileUtil.fileHashCode(pluginHome) - result = 31 * result + recentCommands.hashCode() - result = 31 * result + showWelcomeScreen.hashCode() - result = 31 * result + greetedVersion.hashCode() - result = 31 * result + mainImageModel.hashCode() - result = 31 * result + enableLegacyActions.hashCode() - result = 31 * result + executables.hashCode() - result = 31 * result + userSuppliedModels.hashCode() - result = 31 * result + (googleApiKey?.hashCode() ?: 0) - result = 31 * result + (googleSearchEngineId?.hashCode() ?: 0) - result = 31 * result + (githubToken?.hashCode() ?: 0) - result = 31 * result + (awsProfile?.hashCode() ?: 0) - result = 31 * result + (awsRegion?.hashCode() ?: 0) - result = 31 * result + (awsBucket?.hashCode() ?: 0) - return result - } - - companion object { - val log = LoggerFactory.getLogger(AppSettingsState::class.java) - var auxiliaryLog: File? = null - const val WELCOME_VERSION: String = "1.5.0" - - @JvmStatic - val instance: AppSettingsState by lazy { - ApplicationManager.getApplication()?.getService(AppSettingsState::class.java) ?: AppSettingsState() - } - - fun String.imageModel(): ImageModels { - return ImageModels.values().firstOrNull { - it.modelName == this || it.name == this - } ?: ImageModels.DallE3 - } - - fun getDefaultShell() = if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" - } - - data class UserSuppliedModel( - var displayName: String = "", - var modelId: String = "", - var provider: APIProvider = APIProvider.OpenAI - ) - var analyticsEnabled: Boolean = false -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/MRUItems.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/MRUItems.kt deleted file mode 100644 index b8409ad7..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/MRUItems.kt +++ /dev/null @@ -1,149 +0,0 @@ -package com.github.simiacryptus.aicoder.config - -import com.fasterxml.jackson.annotation.JsonIgnore -import java.io.Serializable -import java.time.Instant -import java.util.concurrent.CopyOnWriteArrayList -import java.util.concurrent.locks.ReentrantReadWriteLock -import kotlin.concurrent.read -import kotlin.concurrent.write -import kotlin.math.min - -class MRUItems : Serializable { - - companion object { - const val DEFAULT_LIMIT = 10 - } - - data class HistoryItem(val instruction: String, var usageCount: Int, var lastUsed: Instant) : Serializable - - val history: MutableList = CopyOnWriteArrayList() - - private val lock = ReentrantReadWriteLock() - - var historyLimit = DEFAULT_LIMIT - set(value) { - require(value > 0) { "History limit must be positive" } - lock.write { - field = value - trimHistories() - } - } - - override fun equals(other: Any?): Boolean { - return other is MRUItems && history == other.history - } - - override fun hashCode(): Int { - return history.hashCode() - } - - fun addInstructionToHistory(instruction: CharSequence) { - lock.write { - val instructionStr = instruction.toString() - val existingItem = history.find { it.instruction == instructionStr } - if (existingItem != null) { - existingItem.usageCount++ - existingItem.lastUsed = Instant.now() - history.remove(existingItem) - history.add(0, existingItem) - } else { - history.add(0, HistoryItem(instructionStr, 1, Instant.now())) - } - trimHistories() - } - } - - @JsonIgnore - fun getMostUsed(limit: Int = DEFAULT_LIMIT): List { - return lock.read { - history - .sortedByDescending { it.usageCount } - .take(min(limit, historyLimit)) - .map { it.instruction } - } - } - - @JsonIgnore - fun getMostRecent(limit: Int = DEFAULT_LIMIT): List { - return lock.read { - history.take(min(limit, historyLimit)).map { it.instruction } - } - } - - @JsonIgnore - fun getMostRecentWithTimestamp(limit: Int = DEFAULT_LIMIT): List> { - return lock.read { - history.take(min(limit, historyLimit)).map { Pair(it.instruction, it.lastUsed) } - } - } - - fun clear() { - lock.write { - history.clear() - } - } - - fun size(): Int = lock.read { history.size } - - fun isEmpty(): Boolean = lock.read { history.isEmpty() } - - fun remove(item: String) { - lock.write { - history.removeIf { it.instruction == item } - } - } - - private fun trimHistories() { - lock.write { - if (history.size > historyLimit) { - history.subList(historyLimit, history.size).clear() - } - } - } - - fun contains(item: String): Boolean { - return lock.read { - history.any { it.instruction == item } - } - } - - @JsonIgnore - fun getUsageCount(item: String): Int { - return lock.read { history.find { it.instruction == item }?.usageCount ?: 0 } - } - - @JsonIgnore - fun getLastUsedTimestamp(item: String): Instant? { - return lock.read { history.find { it.instruction == item }?.lastUsed } - } - - fun merge(other: MRUItems) { - lock.write { - other.history.forEach { otherItem -> - val existingItem = history.find { it.instruction == otherItem.instruction } - if (existingItem != null) { - existingItem.usageCount += otherItem.usageCount - existingItem.lastUsed = maxOf(existingItem.lastUsed, otherItem.lastUsed) - } else { - history.add(otherItem) - } - } - history.sortByDescending { it.lastUsed } - trimHistories() - } - } - - fun removeOlderThan(timestamp: Instant) { - lock.write { - history.removeAll { it.lastUsed.isBefore(timestamp) } - } - } - - override fun toString(): String { - return lock.read { - "MRUItems(mostUsed=${getMostUsed(5)}, mostRecent=${getMostRecent(5)}, size=${history.size})" - } - } - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt deleted file mode 100644 index 3d05db27..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt +++ /dev/null @@ -1,302 +0,0 @@ -package com.github.simiacryptus.aicoder.config - -import com.github.simiacryptus.aicoder.util.IdeaChatClient -import com.github.simiacryptus.aicoder.util.PluginStartupActivity.Companion.addUserSuppliedModels -import com.simiacryptus.jopenai.models.APIProvider -import java.awt.BorderLayout -import java.awt.Dimension -import java.awt.FlowLayout -import java.awt.GridBagConstraints -import java.awt.GridBagLayout -import java.io.File -import java.io.FileOutputStream -import javax.swing.BoxLayout -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JScrollPane -import javax.swing.table.DefaultTableModel - -class StaticAppSettingsConfigurable : AppSettingsConfigurable() { - override fun apply() { - super.apply() - addUserSuppliedModels(settingsInstance.userSuppliedModels) - if (settingsInstance.apiLog) { - val file = File(AppSettingsState.instance.pluginHome, "openai.log") - if (AppSettingsState.auxiliaryLog?.absolutePath?.lowercase() != file.absolutePath.lowercase()) { - file.deleteOnExit() - AppSettingsState.auxiliaryLog = file - IdeaChatClient.instance.logStreams.add(FileOutputStream(file, true).buffered()) - } - } else { - AppSettingsState.auxiliaryLog = null - IdeaChatClient.instance.logStreams.retainAll { it.close(); false } - } - } - - override fun build(component: AppSettingsComponent): JComponent { - val tabbedPane = com.intellij.ui.components.JBTabbedPane() - try {// Basic Settings Tab - val basicSettingsPanel = JPanel(BorderLayout()).apply { - add(JPanel(BorderLayout()).apply { - layout = BoxLayout(this, BoxLayout.Y_AXIS) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Smart Model:")) - add(component.smartModel) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Fast Model:")) - add(component.fastModel) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Image Model:")) - add(component.mainImageModel) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Temperature:")) - add(component.temperature) - }) - add(JPanel(BorderLayout()).apply { - add(JLabel("API Configurations:"), BorderLayout.NORTH) - add(component.apis, BorderLayout.CENTER) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Executables:")) - add(component.executablesPanel) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Human Language:")) - add(component.humanLanguage) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("GitHub Token:")) - add(component.githubToken) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Google API Key:")) - add(component.googleApiKey) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Google Search Engine ID:")) - add(component.googleSearchEngineId) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("AWS Profile:")) - add(component.awsProfile) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("AWS Region:")) - add(component.awsRegion) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("AWS Bucket:")) - add(component.awsBucket) - }) - }) - } - tabbedPane.addTab("Basic Settings", basicSettingsPanel) - } catch (e: Exception) { - log.warn("Error building Basic Settings", e) - } - - tabbedPane.addTab("Developer Tools", JPanel(BorderLayout()).apply { - try { - add(JPanel().apply { - layout = BoxLayout(this, BoxLayout.Y_AXIS) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Developer Tools:")) - add(component.devActions) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Enable Legacy Actions:")) - add(component.enableLegacyActions) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - // Removed sections that reference non-existing components - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Ignore Errors:")) - add(component.suppressErrors) - }) - }, BorderLayout.NORTH) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Edit API Requests:")) - add(component.editRequests) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Disable Auto-Open URLs:")) - add(component.disableAutoOpenUrls) - }) - add(JPanel(BorderLayout()).apply { - add(JLabel("Store Metadata (JSON):"), BorderLayout.NORTH) - val scrollPane = JScrollPane(component.storeMetadata) - scrollPane.preferredSize = Dimension(300, 100) - add(scrollPane, BorderLayout.CENTER) - }) - add(JPanel(BorderLayout()).apply { - add(JLabel("User-Supplied Models:"), BorderLayout.NORTH) - add(JScrollPane(component.userSuppliedModels).apply { - preferredSize = Dimension(500, 200) - }, BorderLayout.CENTER) - add(JPanel(GridBagLayout()).apply { - val gbc = GridBagConstraints().apply { - gridx = 0 - gridy = 0 - fill = GridBagConstraints.HORIZONTAL - weightx = 1.0 - } - add(component.addUserModelButton, gbc) - gbc.gridx++ - add(component.removeUserModelButton, gbc) - }, BorderLayout.SOUTH) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Enable API Log:")) - add(component.apiLog) - add(component.openApiLog) - add(component.clearApiLog) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Server Port:")) - add(component.listeningPort) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Server Endpoint:")) - add(component.listeningEndpoint) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Plugin Home:")) - add(component.pluginHome) - add(component.choosePluginHome) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - add(JLabel("Shell Command:")) - add(component.shellCommand) - }) - add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { - //add(JLabel("Show Welcome Screen:")) - add(component.showWelcomeScreen) - }) - }, BorderLayout.NORTH) - } catch (e: Exception) { - log.warn("Error building Developer Tools", e) - } - }) - - tabbedPane.addTab("Usage", JPanel(BorderLayout()).apply { - try { - add(component.usage, BorderLayout.CENTER) - } catch (e: Exception) { - log.warn("Error building Usage", e) - } - }) - - return tabbedPane - } - - override fun write(settings: AppSettingsState, component: AppSettingsComponent) { - try { - component.githubToken.text = settings.githubToken ?: "" - component.googleApiKey.text = settings.googleApiKey ?: "" - component.googleSearchEngineId.text = settings.googleSearchEngineId ?: "" - component.awsProfile.text = settings.awsProfile ?: "" - component.awsRegion.text = settings.awsRegion ?: "" - component.awsBucket.text = settings.awsBucket ?: "" - component.humanLanguage.text = settings.humanLanguage - component.listeningPort.text = settings.listeningPort.toString() - component.listeningEndpoint.text = settings.listeningEndpoint - component.suppressErrors.isSelected = settings.suppressErrors - component.fastModel.selectedItem = settings.fastModel - component.smartModel.selectedItem = settings.smartModel - component.apiLog.isSelected = settings.apiLog - component.devActions.isSelected = settings.devActions - component.editRequests.isSelected = settings.editRequests - component.mainImageModel.selectedItem = settings.mainImageModel - component.storeMetadata.text = settings.storeMetadata ?: "" - component.temperature.text = settings.temperature.toString() - component.pluginHome.text = settings.pluginHome.absolutePath - component.shellCommand.text = settings.shellCommand - val model = component.apis.model as DefaultTableModel - model.rowCount = 0 // Clear existing rows - APIProvider.values().forEach { value -> - val key = value.name - model.addRow(arrayOf(key, settings.apiKey?.get(key) ?: "", settings.apiBase?.get(key) ?: value.base)) - } - component.showWelcomeScreen.isSelected = settings.showWelcomeScreen - component.enableLegacyActions.isSelected = settings.enableLegacyActions - component.setExecutables(settings.executables) - component.setUserSuppliedModels(settings.userSuppliedModels) - } catch (e: Exception) { - log.warn("Error setting UI", e) - } - } - - override fun read(component: AppSettingsComponent, settings: AppSettingsState) { - try { - settings.githubToken = component.githubToken.text.takeIf { it.isNotBlank() } - settings.googleApiKey = component.googleApiKey.text.takeIf { it.isNotBlank() } - settings.googleSearchEngineId = component.googleSearchEngineId.text.takeIf { it.isNotBlank() } - settings.awsProfile = component.awsProfile.text.takeIf { it.isNotBlank() } - settings.awsRegion = component.awsRegion.text.takeIf { it.isNotBlank() } - settings.awsBucket = component.awsBucket.text.takeIf { it.isNotBlank() } - settings.executables = component.getExecutables().toMutableSet() - settings.humanLanguage = component.humanLanguage.text - settings.listeningPort = component.listeningPort.text.safeInt() - settings.listeningEndpoint = component.listeningEndpoint.text - settings.suppressErrors = component.suppressErrors.isSelected - settings.fastModel = component.fastModel.selectedItem as String - settings.smartModel = component.smartModel.selectedItem as String - settings.apiLog = component.apiLog.isSelected - settings.devActions = component.devActions.isSelected - settings.editRequests = component.editRequests.isSelected - settings.disableAutoOpenUrls = component.disableAutoOpenUrls.isSelected - settings.temperature = component.temperature.text.safeDouble() - settings.storeMetadata = component.storeMetadata.text.takeIf { it.isNotBlank() } - settings.mainImageModel = (component.mainImageModel.selectedItem as String) - settings.pluginHome = File(component.pluginHome.text) - settings.shellCommand = component.shellCommand.text - settings.enableLegacyActions = component.enableLegacyActions.isSelected - - val tableModel = component.apis.model as DefaultTableModel - for (row in 0 until tableModel.rowCount) { - val provider = tableModel.getValueAt(row, 0) as String - val key = tableModel.getValueAt(row, 1) as String - val base = tableModel.getValueAt(row, 2) as String - if (key.isNotBlank()) { - settings.apiKey = settings.apiKey?.toMutableMap()?.apply { put(provider, key) } - settings.apiBase = settings.apiBase?.toMutableMap()?.apply { put(provider, base) } - } else { - settings.apiKey = settings.apiKey?.toMutableMap()?.apply { remove(provider) } - settings.apiBase = settings.apiBase?.toMutableMap()?.apply { remove(provider) } - } - } - settings.showWelcomeScreen = component.showWelcomeScreen.isSelected - settings.userSuppliedModels = component.getUserSuppliedModels().toMutableList() - } catch (e: Exception) { - log.warn("Error reading UI", e) - } - } - - companion object { - val log = com.intellij.openapi.diagnostic.Logger.getInstance(StaticAppSettingsConfigurable::class.java) - } -} - -fun String?.safeInt() = if (null == this) 0 else when { - isEmpty() -> 0 - else -> try { - toInt() - } catch (e: NumberFormatException) { - 0 - } -} - -fun String?.safeDouble() = if (null == this) 0.0 else when { - isEmpty() -> 0.0 - else -> try { - toDouble() - } catch (e: NumberFormatException) { - 0.0 - } - - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/UIAdapter.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/UIAdapter.kt deleted file mode 100644 index 1652089d..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/UIAdapter.kt +++ /dev/null @@ -1,91 +0,0 @@ -package com.github.simiacryptus.aicoder.config - -import com.github.simiacryptus.aicoder.util.UITools -import com.intellij.openapi.Disposable -import com.intellij.openapi.options.Configurable -import org.slf4j.LoggerFactory -import javax.swing.JComponent - -abstract class UIAdapter( - protected val settingsInstance: S, - protected var component: C? = null, -) : Configurable { - - companion object { - private val log = LoggerFactory.getLogger(UIAdapter::class.java) - } - - @Volatile - private var mainPanel: JComponent? = null - override fun getDisplayName(): String { - return "AICoder Settings" - } - - override fun getPreferredFocusedComponent(): JComponent? = null - - override fun createComponent(): JComponent? { - if (null == mainPanel) { - synchronized(this) { - if (null == mainPanel) { - try { - val component = newComponent() - this.component = component - mainPanel = build(component) - write(settingsInstance, component) - } catch (e: Exception) { - log.error("Error creating component", e) - } - } - } - } - return mainPanel - } - - abstract fun newComponent(): C - abstract fun newSettings(): S - private fun getSettings(component: C? = this.component) = try { - when (component) { - null -> settingsInstance - else -> { - val buffer = newSettings() - read(component, buffer) - buffer - } - } - } catch (e: Exception) { - log.error("Error reading settings", e) - settingsInstance - } - - override fun isModified() = when { - component == null -> false - getSettings() != settingsInstance -> true - else -> false - } - - override fun apply() { - if (component != null) read(component!!, settingsInstance) - } - - override fun reset() { - if (component != null) write(settingsInstance, component!!) - } - - override fun disposeUIResources() { - val component = component - this.component = null - if (component != null && component is Disposable) component.dispose() - } - - open fun build(component: C): JComponent = - UITools.buildFormViaReflection(component, false)!! - - open fun read(component: C, settings: S) { - UITools.readKotlinUIViaReflection(component, settings) - } - - open fun write(settings: S, component: C) { - UITools.writeKotlinUIViaReflection(settings, component) - } - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/UsageTable.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/config/UsageTable.kt deleted file mode 100644 index 4e2cd908..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/UsageTable.kt +++ /dev/null @@ -1,120 +0,0 @@ -package com.github.simiacryptus.aicoder.config - -import com.github.simiacryptus.aicoder.util.IdeaChatClient -import com.intellij.ui.components.JBScrollPane -import com.intellij.ui.table.JBTable -import com.simiacryptus.skyenet.core.platform.model.UsageInterface -import org.jdesktop.swingx.JXTable -import java.awt.BorderLayout -import java.awt.event.ActionEvent -import java.util.* -import javax.swing.AbstractAction -import javax.swing.JButton -import javax.swing.JPanel -import javax.swing.table.AbstractTableModel -import javax.swing.table.DefaultTableCellRenderer - -class UsageTable( - val usage: UsageInterface -) : JPanel(BorderLayout()) { - - private val buttonPanel = JPanel() - val columnNames = arrayOf("Model", "Prompt", "Completion", "Cost") - - val rowData by lazy { - usage.getUserUsageSummary(IdeaChatClient.localUser).map { entry -> - listOf( - entry.key.modelName, - entry.value.prompt_tokens.toString(), - entry.value.completion_tokens.toString(), - String.format("%.2f", entry.value.cost) - ).toMutableList() - }.toMutableList() - } - - private val dataModel by lazy { - object : AbstractTableModel() { - override fun getColumnName(column: Int): String { - return columnNames.get(column).toString() - } - - override fun getRowCount(): Int { - return rowData.size - } - - override fun getColumnCount(): Int { - return columnNames.size - } - - override fun getValueAt(row: Int, col: Int): Any { - return rowData[row][col] - } - - override fun isCellEditable(row: Int, column: Int): Boolean { - return true - } - - override fun setValueAt(value: Any, row: Int, col: Int) { - rowData[row][col] = value.toString() - fireTableCellUpdated(row, col) - } - - } - } - - private val jtable by lazy { JBTable(dataModel) } - - private val scrollpane by lazy { JBScrollPane(jtable) } - - - private val clearButton by lazy { - JButton(object : AbstractAction("Clear") { - override fun actionPerformed(e: ActionEvent?) { - rowData.clear() - usage.clear() - this@UsageTable.parent.invalidate() - } - }) - } - - init { - jtable.columnModel.getColumn(0).cellRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(1).cellRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(2).cellRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(3).cellRenderer = DefaultTableCellRenderer() - - val editor = object : JXTable.GenericEditor() { - override fun isCellEditable(anEvent: EventObject?) = false - } - jtable.columnModel.getColumn(0).cellEditor = editor - jtable.columnModel.getColumn(1).cellEditor = editor - jtable.columnModel.getColumn(2).cellEditor = editor - jtable.columnModel.getColumn(3).cellEditor = editor - - jtable.columnModel.getColumn(0).headerRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(1).headerRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(2).headerRenderer = DefaultTableCellRenderer() - jtable.columnModel.getColumn(3).headerRenderer = DefaultTableCellRenderer() - - // Set the preferred width for the first column (checkboxes) to the header label width - initCol(0) - initCol(1) - initCol(2) - initCol(3) - - jtable.tableHeader.defaultRenderer = DefaultTableCellRenderer() - - add(scrollpane, BorderLayout.CENTER) - buttonPanel.add(clearButton) - add(buttonPanel, BorderLayout.SOUTH) - } - - private fun initCol(idx: Int) { - val headerRenderer = jtable.tableHeader.defaultRenderer - val headerValue = jtable.columnModel.getColumn(idx).headerValue - val headerComp = headerRenderer.getTableCellRendererComponent(jtable, headerValue, false, false, 0, idx) - jtable.columnModel.getColumn(idx).preferredWidth = headerComp.preferredSize.width - } - - companion object -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/ui/TokenCountWidgetFactory.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/ui/TokenCountWidgetFactory.kt deleted file mode 100644 index fb5c406d..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/ui/TokenCountWidgetFactory.kt +++ /dev/null @@ -1,132 +0,0 @@ -package com.github.simiacryptus.aicoder.ui - -import com.intellij.openapi.editor.event.DocumentEvent -import com.intellij.openapi.editor.event.DocumentListener -import com.intellij.openapi.editor.event.SelectionEvent -import com.intellij.openapi.editor.event.SelectionListener -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.fileEditor.FileEditorManagerEvent -import com.intellij.openapi.fileEditor.FileEditorManagerListener -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.readText -import com.intellij.openapi.wm.StatusBar -import com.intellij.openapi.wm.StatusBarWidget -import com.intellij.openapi.wm.StatusBarWidgetFactory -import com.simiacryptus.jopenai.util.GPT4Tokenizer -import kotlinx.coroutines.CoroutineScope -import java.awt.event.MouseEvent -import java.util.concurrent.LinkedBlockingDeque -import java.util.concurrent.ThreadPoolExecutor -import java.util.concurrent.TimeUnit - -class TokenCountWidgetFactory : StatusBarWidgetFactory { - companion object { - val workQueue = LinkedBlockingDeque() - val pool = ThreadPoolExecutor( - /* corePoolSize = */ 1, /* maximumPoolSize = */ 1, - /* keepAliveTime = */ 60L, /* unit = */ TimeUnit.SECONDS, - /* workQueue = */ workQueue - ) - } - - class TokenCountWidget : StatusBarWidget, StatusBarWidget.TextPresentation { - - private var tokenCount: Int = 0 - val codex = GPT4Tokenizer(false) - - override fun ID(): String { - return "StatusBarComponent" - } - - override fun getPresentation(): StatusBarWidget.WidgetPresentation { - return this - } - - override fun install(statusBar: StatusBar) { - val connection = statusBar.project?.messageBus?.connect() - connection?.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, object : FileEditorManagerListener { - override fun selectionChanged(event: FileEditorManagerEvent) { - update(statusBar) { - codex.estimateTokenCount((event.newFile ?: event.oldFile)?.readText() ?: "") - } - - val editor = FileEditorManager.getInstance(statusBar.project!!).selectedTextEditor - editor?.document?.addDocumentListener(object : DocumentListener { - override fun documentChanged(event: DocumentEvent) { - update(statusBar) { codex.estimateTokenCount(editor.document.text) } - } - }) - - editor?.selectionModel?.addSelectionListener(object : SelectionListener { - override fun selectionChanged(event: SelectionEvent) { - update(statusBar) { - val newTokens = event.newRanges?.map { - codex.estimateTokenCount( - event.editor.document.text.substring( - it.startOffset, - it.endOffset - ) - ) - }?.sum() ?: 0 - newTokens - } - } - }) - } - }) - } - - private fun update(statusBar: StatusBar, tokens: () -> Int) { - workQueue.clear() - pool.submit { - tokenCount = tokens() - statusBar.updateWidget(ID()) - } - } - - override fun dispose() { - //connection?.disconnect() - } - - - override fun getText(): String { - return "$tokenCount Tokens" - } - - override fun getTooltipText(): String { - return "Current file token count" - } - - override fun getAlignment(): Float { - return 0.5f - } - - override fun getClickConsumer(): com.intellij.util.Consumer? = null - - - } - - override fun getId(): String { - return "StatusBarComponent" - } - - override fun getDisplayName(): String { - return "Token Counter" - } - - override fun createWidget(project: Project, scope: CoroutineScope): StatusBarWidget { - return TokenCountWidget() - } - - override fun createWidget(project: Project): StatusBarWidget { - return TokenCountWidget() - } - - override fun isAvailable(project: Project): Boolean { - return true - } - - override fun canBeEnabledOn(statusBar: StatusBar): Boolean { - return true - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/BlockComment.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/BlockComment.kt deleted file mode 100644 index 7ebade48..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/BlockComment.kt +++ /dev/null @@ -1,56 +0,0 @@ -@file:Suppress("NAME_SHADOWING") - -package com.github.simiacryptus.aicoder.util - -import com.github.simiacryptus.aicoder.util.TextBlock.Companion.DELIMITER -import com.github.simiacryptus.aicoder.util.TextBlock.Companion.TAB_REPLACEMENT -import com.simiacryptus.util.StringUtil -import java.util.* -import java.util.stream.Collectors - -class BlockComment( - private val blockPrefix: CharSequence, - private val linePrefix: CharSequence, - private val blockSuffix: CharSequence, - indent: CharSequence, - vararg textBlock: CharSequence -) : - IndentedText(indent, *textBlock) { - class Factory(private val blockPrefix: String, private val linePrefix: String, private val blockSuffix: String) : - TextBlockFactory { - override fun fromString(text: String?): BlockComment { - var text = text!! - text = StringUtil.stripSuffix( - StringUtil.trimSuffix(text.replace("\t", TAB_REPLACEMENT.toString(), false)), - blockSuffix.trim { it <= ' ' }) - val indent = StringUtil.getWhitespacePrefix(*text.split(DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray()) - return BlockComment(blockPrefix, - linePrefix, - blockSuffix, - indent, - *(Arrays.stream(text.split(DELIMITER.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) - .map { s: CharSequence? -> StringUtil.stripPrefix(s!!, indent) } - .map { text: CharSequence? -> StringUtil.trimPrefix(text!!) } - .map { s: CharSequence? -> StringUtil.stripPrefix(s!!, blockPrefix.trim { it <= ' ' }) } - .map { s: CharSequence? -> StringUtil.stripPrefix(s!!, linePrefix.trim { it <= ' ' }) } - .collect(Collectors.toList()).toTypedArray())) - } - - override fun looksLike(text: String?): Boolean { - return text!!.trim { it <= ' ' }.startsWith(blockPrefix) && text.trim { it <= ' ' }.endsWith(blockSuffix) - } - } - - override fun toString(): String { - val indent = this.indent - val delimiter: CharSequence = DELIMITER + indent - val joined: CharSequence = Arrays.stream(rawString()).map { x: CharSequence -> "$linePrefix $x" } - .collect(Collectors.joining(delimiter)) - return blockPrefix.toString() + delimiter + joined + delimiter + blockSuffix - } - - override fun withIndent(indent: CharSequence): IndentedText { - return BlockComment(blockPrefix, linePrefix, blockSuffix, indent, *lines) - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/BrowseUtil.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/BrowseUtil.kt deleted file mode 100644 index 936d51a2..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/BrowseUtil.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.ui.SettingsWidgetFactory.SettingsWidget -import org.slf4j.LoggerFactory -import java.awt.Desktop -import java.net.DatagramPacket -import java.net.DatagramSocket -import java.net.InetAddress -import java.net.URI - -object BrowseUtil { - - fun browse(uri: URI) { - SettingsWidget()?.updateSessionsList() - sendUdpMessage(uri.toString()) - if (!AppSettingsState.instance.disableAutoOpenUrls && Desktop.isDesktopSupported()) { - val desktop = Desktop.getDesktop() - if (desktop.isSupported(Desktop.Action.BROWSE)) { - desktop.browse(uri) - } - } - } - - var NOTIFICATION_PORT: Int? = 41390 - private fun sendUdpMessage(message: String) { - try { - log.info("Sending UDP message: $message") - val address = InetAddress.getByName("localhost") - val buf = message.toByteArray() - val packet = DatagramPacket(buf, buf.size, address, NOTIFICATION_PORT ?: return) - val socket = DatagramSocket() - socket.send(packet) - socket.close() - } catch (e: Exception) { - log.warn("Error sending UDP message", e) - } - } - - val log = LoggerFactory.getLogger(BrowseUtil::class.java) - - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeChatSocketManager.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeChatSocketManager.kt deleted file mode 100644 index b08c5daf..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeChatSocketManager.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.simiacryptus.jopenai.ChatClient -import com.simiacryptus.jopenai.models.ChatModel -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.StorageInterface -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.skyenet.webui.application.ApplicationServer -import com.simiacryptus.skyenet.webui.chat.ChatSocketManager - -open class CodeChatSocketManager( - session: Session, - val language: String, - val filename: String, - val codeSelection: String, - api: ChatClient, - model: ChatModel, - storage: StorageInterface?, -) : ChatSocketManager( - session = session, - model = model, - userInterfacePrompt = """ - |# `$filename` - | - |```$language - |$codeSelection - |``` - """.trimMargin().trim(), - systemPrompt = """ - |You are a helpful AI that helps people with coding. - | - |You will be answering questions about the following code located in `$filename`: - | - |```$language - |$codeSelection - |``` - | - |Responses may use markdown formatting, including code blocks. - """.trimMargin(), - api = api, - applicationClass = ApplicationServer::class.java, - storage = storage, -) { - override fun canWrite(user: User?): Boolean = true -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeProcessingUtils.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeProcessingUtils.kt deleted file mode 100644 index 316e1058..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/CodeProcessingUtils.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import java.io.File -import java.nio.file.Path - -object CodeProcessingUtils { - - fun extractCode(code: String): String { - return code.trim().let { - "(?s)```[^\\n]*\n(.*)\n```".toRegex().find(it)?.groupValues?.get(1) ?: it - } - } - - fun codeSummary(codeFiles: Set, root: File): String { - return codeFiles.filter { - val name = it.fileName.toString().lowercase() - !(name.endsWith(".png") || name.endsWith(".jpg")) - }.joinToString("\n\n") { path -> - "# $path\n```${path.toString().split('.').last()}\n${root.resolve(path.toFile()).readText()}\n```" - } - } - - fun formatCodeWithLineNumbers(code: String): String { - return code.split("\n").withIndex().joinToString("\n") { (i, line) -> - "${i.toString().padStart(3, '0')} $line" - } - } - - fun getSuffixForContext(text: String, idealLength: Int): String { - return text.takeLast(idealLength).replace('\n', ' ') - } - - fun getPrefixForContext(text: String, idealLength: Int): String { - return text.take(idealLength).replace('\n', ' ') - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/ComputerLanguage.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/ComputerLanguage.kt deleted file mode 100644 index 5e128cdc..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/ComputerLanguage.kt +++ /dev/null @@ -1,483 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import java.util.* - -enum class ComputerLanguage(configuration: Configuration) { - Java( - Configuration() - .setDocumentationStyle("JavaDoc") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", " * ", " */")) - .setFileExtensions("java") - ), - Cpp( - Configuration() - .setDocumentationStyle("Doxygen") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("cpp") - ), - LUA( - Configuration() - .setDocumentationStyle("LuaDoc") - .setLineComments(LineComment.Factory("--")) - .setBlockComments(BlockComment.Factory("--[[", "", "]]")) - .setDocComments(BlockComment.Factory("---[[", "", "]]")) - .setFileExtensions("lua") - ), - SVG( - Configuration() - .setDocumentationStyle("SVG") - .setLineComments(LineComment.Factory("")) - .setDocComments(BlockComment.Factory("")) - .setFileExtensions("svg") - ), - OpenSCAD( - Configuration() - .setDocumentationStyle("OpenSCAD") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("scad") - ), - Bash( - Configuration() - .setLineComments(LineComment.Factory("#")) - .setFileExtensions("sh") - ), - Markdown( - Configuration() - .setDocumentationStyle("Markdown") - .setLineComments(BlockComment.Factory("")) - .setBlockComments(BlockComment.Factory("")) - .setDocComments(BlockComment.Factory("")) - .setFileExtensions("md") - ), - Text( - Configuration() - .setDocumentationStyle("Text") - .setLineComments(LineComment.Factory("#")) - .setFileExtensions("txt") - ), - XML( - Configuration() - .setDocumentationStyle("XML") - .setLineComments(BlockComment.Factory("")) - .setBlockComments(BlockComment.Factory("")) - .setDocComments(BlockComment.Factory("")) - .setFileExtensions("xml") - ), - Ada( - Configuration() - .setLineComments(LineComment.Factory("--")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("ada") - ), - Assembly( - Configuration() - .setLineComments(LineComment.Factory(";")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("assembly", "asm") - ), - Basic( - Configuration() - .setLineComments(LineComment.Factory("'")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("basic", "bs") - ), - C( - Configuration() - .setDocumentationStyle("Doxygen") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("c") - ), - Clojure( - Configuration() - .setDocumentationStyle("ClojureDocs") - .setLineComments(LineComment.Factory(";")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("cj") - ), - COBOL( - Configuration() - .setLineComments(LineComment.Factory("*")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("cobol", "cob") - ), - CSharp( - Configuration() - .setDocumentationStyle("XML") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("cs", "c#") - ), - CSS( - Configuration() - .setLineComments(BlockComment.Factory("/*", "", "*/")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("css") - ), - Dart( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("dart") - ), - Delphi( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("delphi") - ), - Erlang( - Configuration() - .setLineComments(LineComment.Factory("%")) - .setBlockComments(BlockComment.Factory("%%", "", "%%")) - .setDocComments(BlockComment.Factory("%%%", "%", "%%%")) - .setFileExtensions("erl") - ), - Elixir( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("elixir") - ), - FORTRAN( - Configuration() - .setLineComments(LineComment.Factory("!")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("f", "for", "ftn", "f77", "f90", "f95", "f03", "f08") - ), - FSharp( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("f#") - ), - Go( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("go") - ), - Groovy( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("groovy", "gradle") - ), - Haskell( - Configuration() - .setLineComments(LineComment.Factory("--")) - .setBlockComments(BlockComment.Factory("{-", "-}", "{- -}")) - .setDocComments(BlockComment.Factory("{-|", "|-}", "{-| -}")) - .setFileExtensions("hs") - ), - HTML( - Configuration() - .setLineComments(BlockComment.Factory("")) - .setBlockComments(BlockComment.Factory("")) - .setDocComments(BlockComment.Factory("")) - .setFileExtensions("html") - ), - Julia( - Configuration() - .setLineComments(LineComment.Factory("#")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("julia") - ), - JavaScript( - Configuration() - .setDocumentationStyle("JSDoc") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("js", "javascript") - ), - Json( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setFileExtensions("json") - ), - Kotlin( - Configuration() - .setDocumentationStyle("KDoc") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("kt", "kts") - ), - Lisp( - Configuration() - .setLineComments(LineComment.Factory(";")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("lisp") - ), - Logo( - Configuration() - .setLineComments(LineComment.Factory(";")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("logo", "log") - ), - MATLAB( - Configuration() - .setLineComments(LineComment.Factory("%")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("matlab", "m") - ), - OCaml( - Configuration() - .setLineComments(LineComment.Factory("(Params.create(*")) - .setBlockComments(BlockComment.Factory("*))", "", "ocaml")) - .setDocComments(BlockComment.Factory("*))", "", "ocaml")) - .setFileExtensions("ml") - ), - Pascal( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("pascal", "pas") - ), - PHP( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("php") - ), - Perl( - Configuration() - .setDocumentationStyle("POD") - .setLineComments(LineComment.Factory("#")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("perl", "pl") - ), - Prolog( - Configuration() - .setLineComments(LineComment.Factory("%")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("prolog") - ), - Python( - Configuration() - .setDocumentationStyle("PyDoc") - .setLineComments(LineComment.Factory("#")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("py", "python") - ), - R( - Configuration() - .setLineComments(LineComment.Factory("#")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("r") - ), - Ruby( - Configuration() - .setLineComments(LineComment.Factory("#")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("ruby", "rb") - ), - Racket( - Configuration() - .setLineComments(LineComment.Factory("#")) - .setBlockComments(BlockComment.Factory("#|", "", "|#")) - .setDocComments(BlockComment.Factory("#|", "", "|#")) - .setFileExtensions("racket") - ), - Rust( - Configuration() - .setDocumentationStyle("Rustdoc") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("rs", "rust") - ), - Scala( - Configuration() - .setDocumentationStyle("ScalaDoc") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("scala", "sc") - ), - Scheme( - Configuration() - .setLineComments(LineComment.Factory(";")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("scheme") - ), - SCSS( - Configuration() - .setDocumentationStyle("SCSS") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(LineComment.Factory("///")) - .setFileExtensions("scss") - ), - SQL( - Configuration() - .setLineComments(LineComment.Factory("--")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("sql") - ), - Smalltalk( - Configuration() - .setLineComments(LineComment.Factory("\"")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("smalltalk", "st") - ), - Swift( - Configuration() - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("swift") - ), - Tcl( - Configuration() - .setLineComments(LineComment.Factory("#")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("tcl") - ), - TypeScript( - Configuration() - .setDocumentationStyle("TypeDoc") - .setLineComments(LineComment.Factory("//")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("typescript", "ts") - ), - VisualBasic( - Configuration() - .setLineComments(LineComment.Factory("'")) - .setBlockComments(BlockComment.Factory("/*", "", "*/")) - .setDocComments(BlockComment.Factory("/**", "*", "*/")) - .setFileExtensions("visualbasic", "vb") - ), - YAML( - Configuration() - .setLineComments(LineComment.Factory("#")) - .setFileExtensions("yaml") - ), - ZShell( - Configuration() - .setLineComments(LineComment.Factory("#")) - .setFileExtensions("zsh") - ); - - val extensions: List - val docStyle: String - val lineComment: TextBlockFactory<*> - val blockComment: TextBlockFactory<*> - private val docComment: TextBlockFactory<*> - - init { - extensions = listOf(*configuration.fileExtensions) - docStyle = configuration.documentationStyle - lineComment = configuration.lineComments!! - blockComment = configuration.getBlockComments()!! - docComment = configuration.getDocComments()!! - } - - fun getCommentModel(text: String?): TextBlockFactory<*> { - if (Objects.requireNonNull(docComment)!!.looksLike(text)) return docComment - return if (Objects.requireNonNull(blockComment)!!.looksLike(text)) blockComment else lineComment - } - - internal class Configuration { - var documentationStyle = "" - private set - var fileExtensions = arrayOf() - private set - var lineComments: TextBlockFactory<*>? = null - private set - private var blockComments: TextBlockFactory<*>? = null - private var docComments: TextBlockFactory<*>? = null - fun setDocumentationStyle(documentationStyle: String): Configuration { - this.documentationStyle = documentationStyle - return this - } - - fun setFileExtensions(vararg fileExtensions: CharSequence): Configuration { - @Suppress("UNCHECKED_CAST") - this.fileExtensions = fileExtensions as Array - return this - } - - fun setLineComments(lineComments: TextBlockFactory<*>): Configuration { - this.lineComments = lineComments - return this - } - - fun getBlockComments(): TextBlockFactory<*>? { - return if (null == blockComments) lineComments else blockComments - } - - fun setBlockComments(blockComments: TextBlockFactory<*>): Configuration { - this.blockComments = blockComments - return this - } - - fun getDocComments(): TextBlockFactory<*>? { - return if (null == docComments) getBlockComments() else docComments - } - - fun setDocComments(docComments: TextBlockFactory<*>): Configuration { - this.docComments = docComments - return this - } - } - - companion object { - @JvmStatic - fun findByExtension(extension: CharSequence): ComputerLanguage? { - return Arrays.stream(values()).filter { x: ComputerLanguage -> - x.extensions.contains( - extension - ) - }.findAny().orElse(null) - } - - @JvmStatic - fun getComputerLanguage(e: AnActionEvent?): ComputerLanguage? { - val file = e?.getData(CommonDataKeys.VIRTUAL_FILE) ?: return null - val extension = if (file.extension != null) file.extension!!.lowercase(Locale.getDefault()) else "" - return findByExtension(extension) - } - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/FileUtils.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/FileUtils.kt deleted file mode 100644 index 61fff3c7..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/FileUtils.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.intellij.openapi.vfs.VirtualFile - -fun VirtualFile.findRecursively(predicate: (VirtualFile) -> Boolean): List { - val results = mutableListOf() - if (this.isDirectory) { - this.children?.forEach { child -> - if (child.isDirectory) { - results.addAll(child.findRecursively(predicate)) - } else if (predicate(child)) { - results.add(child) - } - } - } else if (predicate(this)) { - results.add(this) - } - return results -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaChatClient.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaChatClient.kt deleted file mode 100644 index 89fa6fb0..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaChatClient.kt +++ /dev/null @@ -1,238 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.ui.components.JBScrollPane -import com.intellij.util.ui.FormBuilder -import com.simiacryptus.jopenai.ChatClient -import com.simiacryptus.jopenai.models.APIProvider -import com.simiacryptus.jopenai.models.ApiModel.* -import com.simiacryptus.jopenai.models.OpenAIModel -import com.simiacryptus.jopenai.models.TextModel -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import com.simiacryptus.skyenet.core.platform.Session -import com.simiacryptus.skyenet.core.platform.model.User -import com.simiacryptus.util.JsonUtil -import org.apache.hc.core5.http.HttpRequest -import org.slf4j.LoggerFactory -import org.slf4j.event.Level -import java.io.File -import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicReference -import javax.swing.JPanel -import javax.swing.JTextArea - - -open class IdeaChatClient( - key: Map = AppSettingsState.instance.apiKey?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() - ?.associate { it.key to it.value } ?: mapOf(), - apiBase: Map = AppSettingsState.instance.apiBase?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() - ?.associate { it.key to it.value } ?: mapOf(), -) : ChatClient( - key = key, - apiBase = apiBase, -) { - - init { - //log.info("Initializing OpenAI Client", Throwable()) - require(key.size == apiBase.size) { - "API Key not configured for all providers: ${key.keys} != ${APIProvider.values().toList()}" - } - } - - private class IdeaChildClient( - val inner: IdeaChatClient, - key: Map, - apiBase: Map - ) : IdeaChatClient( - key = key, - apiBase = apiBase - ) { - override fun log(level: Level, msg: String) { - super.log(level, msg) - inner.log(level, msg) - } - } - - override fun getChildClient(): ChatClient = IdeaChildClient(inner = this, key = key, apiBase = apiBase).apply { - session = inner.session - user = inner.user - } - - private val isInRequest = AtomicBoolean(false) - - override fun onUsage(model: OpenAIModel?, tokens: Usage) { -// AppSettingsState.instance.tokenCounter += tokens.total_tokens - ApplicationServices.usageManager.incrementUsage(currentSession, localUser, model!!, tokens) - } - - override fun authorize(request: HttpRequest, apiProvider: APIProvider) { - val checkApiKey = UITools.checkApiKey(key.get(apiProvider) ?: throw IllegalArgumentException("No API Key for $apiProvider")) - key = key.toMutableMap().let { - it[apiProvider] = checkApiKey - it - }.entries.toTypedArray().associate { it.key to it.value } - super.authorize(request, apiProvider) - } - - @Suppress("NAME_SHADOWING") - override fun chat( - chatRequest: ChatRequest, - model: TextModel - ): ChatResponse { - val storeMetadata = AppSettingsState.instance.storeMetadata - var chatRequest = chatRequest.copy( - store = storeMetadata?.let { it.isNotBlank() }, - metadata = storeMetadata?.let { JsonUtil.fromJson(it, Map::class.java) } - ) - val lastEvent = lastEvent - lastEvent ?: return super.chat(chatRequest, model) - chatRequest = chatRequest.copy( - store = chatRequest.store, - metadata = chatRequest.metadata?.let { - it + mapOf( - "project" to lastEvent.project?.name, - "action" to lastEvent.presentation.text, - "language" to lastEvent.getData(CommonDataKeys.PSI_FILE)?.language?.displayName, - ) - } - ) - if (isInRequest.getAndSet(true)) { - val response = super.chat(chatRequest, model) - if (null != response.usage) { - UITools.logAction( - """ - |Chat Response: ${JsonUtil.toJson(response.usage!!)} - """.trimMargin().trim() - ) - } - return response - } else { - try { - if (!AppSettingsState.instance.editRequests) { - val response = super.chat(chatRequest, model) - if (null != response.usage) { - UITools.logAction( - """ - |Chat Response: ${JsonUtil.toJson(response.usage!!)} - """.trimMargin().trim() - ) - } - return response - } - return withJsonDialog(chatRequest, { chatRequest -> - UITools.run( - lastEvent.project, "OpenAI Request", true, suppressProgress = false - ) { - val response = super.chat(chatRequest, model) - if (null != response.usage) { - UITools.logAction( - """ - |Chat Response: ${JsonUtil.toJson(response.usage!!)} - """.trimMargin().trim() - ) - } - response - } - }, "Edit Chat Request") - } finally { - isInRequest.set(false) - } - } - } - - - companion object { - - val instance by lazy { - //log.info("Initializing OpenAI Client", Throwable()) - val client = IdeaChatClient() - if (AppSettingsState.instance.apiLog) { - try { - val file = File(AppSettingsState.instance.pluginHome, "openai.log") - file.parentFile.mkdirs() - AppSettingsState.auxiliaryLog = file - client.logStreams.add(java.io.FileOutputStream(file, file.exists()).buffered()) - } catch (e: Exception) { - log.warn("Error initializing log file", e) - } - } - client - } - - var lastEvent: AnActionEvent? = null - private fun uiEdit( - project: Project? = null, - title: String = "Edit Request", - jsonTxt: String - ): String { - return execute { - val json = JTextArea( - /* text = */ "", - /* rows = */ 3, - /* columns = */ 120 - ) - json.isEditable = true - json.lineWrap = false - val jbScrollPane = JBScrollPane(json) - jbScrollPane.horizontalScrollBarPolicy = JBScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - jbScrollPane.verticalScrollBarPolicy = JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED - val dialog = object : DialogWrapper(project) { - init { - this.init() - this.title = title - this.setOKButtonText("OK") - this.setCancelButtonText("Cancel") - this.isResizable = true - } - - override fun createCenterPanel(): JPanel? { - val formBuilder = FormBuilder.createFormBuilder() - formBuilder.addLabeledComponentFillVertically("JSON", jbScrollPane) - return formBuilder.panel - } - } - json.text = jsonTxt - dialog.show() - log.warn("dialog.size = " + dialog.size) - if (!dialog.isOK) { - throw RuntimeException("Cancelled") - } - json.text - } ?: jsonTxt - } - - private fun execute( - fn: () -> T - ): T? { - val application = ApplicationManager.getApplication() - val ref: AtomicReference = AtomicReference() - if (null != application) { - application.invokeAndWait { ref.set(fn()) } - } else { - ref.set(fn()) - } - return ref.get() - } - - - fun withJsonDialog( - request: T, - function: (T) -> V, - title: String - ): V { - val project = lastEvent?.project ?: return function(request) - return function(JsonUtil.fromJson(uiEdit(project, title, JsonUtil.toJson(request)), request::class.java)) - } - - private val log = LoggerFactory.getLogger(IdeaChatClient::class.java) - val currentSession = Session.newGlobalID() - val localUser = User(id = "1", email = "user@localhost") - } - -} - diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaOpenAIClient.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaOpenAIClient.kt deleted file mode 100644 index ff84ea18..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/IdeaOpenAIClient.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.simiacryptus.jopenai.OpenAIClient -import com.simiacryptus.jopenai.models.APIProvider -import com.simiacryptus.jopenai.models.ApiModel -import com.simiacryptus.jopenai.models.OpenAIModel -import com.simiacryptus.skyenet.core.platform.ApplicationServices -import org.apache.hc.core5.http.HttpRequest -import org.slf4j.LoggerFactory -import java.io.File -import java.util.concurrent.atomic.AtomicBoolean - -class IdeaOpenAIClient : OpenAIClient( - key = AppSettingsState.instance.apiKey?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() - ?.associate { it.key to it.value } ?: mapOf(), - apiBase = AppSettingsState.instance.apiBase?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() - ?.associate { it.key to it.value } ?: mapOf(), -) { - - init { - //log.info("Initializing OpenAI Client", Throwable()) - require(key.size == apiBase.size) { - "API Key not configured for all providers: ${key.keys} != ${APIProvider.values().toList()}" - } - } - - private val isInRequest = AtomicBoolean(false) - - override fun onUsage(model: OpenAIModel?, tokens: ApiModel.Usage) { -// AppSettingsState.instance.tokenCounter += tokens.total_tokens - ApplicationServices.usageManager.incrementUsage( - IdeaChatClient.currentSession, - IdeaChatClient.localUser, model!!, tokens - ) - } - - override fun authorize(request: HttpRequest, apiProvider: APIProvider) { - val checkApiKey = - UITools.checkApiKey(key.get(apiProvider) ?: throw IllegalArgumentException("No API Key for $apiProvider")) - key = key.toMutableMap().let { - it[apiProvider] = checkApiKey - it - }.entries.toTypedArray().associate { it.key to it.value } - super.authorize(request, apiProvider) - } - - companion object { - - val instance by lazy { - //log.info("Initializing OpenAI Client", Throwable()) - val client = IdeaOpenAIClient() - if (AppSettingsState.instance.apiLog) { - try { - val file = File(AppSettingsState.instance.pluginHome, "openai.log") - file.parentFile.mkdirs() - AppSettingsState.auxiliaryLog = file - client.logStreams.add(java.io.FileOutputStream(file, file.exists()).buffered()) - } catch (e: Exception) { - log.warn("Error initializing log file", e) - } - } - client - } - val log = LoggerFactory.getLogger(IdeaOpenAIClient::class.java) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/IndentedText.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/IndentedText.kt deleted file mode 100644 index df205963..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/IndentedText.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.simiacryptus.util.StringUtil - -/** - * This class provides a way to store and manipulate indented text blocks. - * - * The text block is stored as a single string, with each line separated by a newline character. - * The indentation is stored as a separate string, which is prepended to each line when the text block is converted to a string. - * - * The class provides a companion object method to convert a string to an IndentedText object. - * This method replaces all tab characters with two spaces, and then finds the minimum indentation of all lines. - * This indentation is then used as the indentation for the IndentedText object. - * - * The class also provides a method to create a new IndentedText object with a different indentation. - */ -open class IndentedText(var indent: CharSequence, vararg val lines: CharSequence) : TextBlock { - - override fun toString(): String { - return rawString().joinToString(TextBlock.DELIMITER + indent) - } - - override fun withIndent(indent: CharSequence): IndentedText { - return IndentedText(indent, *lines) - } - - override fun rawString(): Array { - return lines - } - - companion object { - /** - * This method is used to convert a string into an IndentedText object. - * - * @param text The string to be converted into an IndentedText object. - * @return IndentedText object created from the input string. - */ - fun fromString(text: String?): IndentedText { - val processedText = (text ?: "").replace("\t", TextBlock.TAB_REPLACEMENT.toString()) - val lines = processedText.split(TextBlock.DELIMITER) - val indent = StringUtil.getWhitespacePrefix(*lines.toTypedArray()) - return IndentedText(indent, *lines.map { StringUtil.stripPrefix(it, indent) }.toTypedArray()) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/LanguageUtils.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/LanguageUtils.kt deleted file mode 100644 index 0d5490d6..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/LanguageUtils.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.github.simiacryptus.aicoder.actions.generic.toFile -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.PsiManager -import java.util.* - -object LanguageUtils { - - fun isLanguageSupported(computerLanguage: ComputerLanguage?): Boolean { - return computerLanguage != null - } - - fun getComputerLanguage(e: AnActionEvent): ComputerLanguage? { - return ApplicationManager.getApplication().runReadAction { - val editor = e.getData(CommonDataKeys.EDITOR) ?: return@runReadAction null - val virtualFile: VirtualFile = FileDocumentManager.getInstance().getFile(editor.document) ?: return@runReadAction null - val file = PsiManager.getInstance(e.project!!).findFile(virtualFile)?.virtualFile?.toFile ?: return@runReadAction null - val extension = if (file.extension != null) file.extension.lowercase(Locale.getDefault()) else "" - return@runReadAction ComputerLanguage.findByExtension(extension) - } - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/LineComment.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/LineComment.kt deleted file mode 100644 index 39df52dc..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/LineComment.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.simiacryptus.util.StringUtil.getWhitespacePrefix -import com.simiacryptus.util.StringUtil.stripPrefix -import com.simiacryptus.util.StringUtil.trimPrefix -import java.util.* -import java.util.stream.Collectors - -class LineComment(private val commentPrefix: CharSequence, indent: CharSequence?, vararg lines: CharSequence) : - IndentedText(indent!!, *lines) { - class Factory(private val commentPrefix: String) : TextBlockFactory { - override fun fromString(text: String?): LineComment { - var textVar = text - textVar = textVar!!.replace(Regex("\t"), TextBlock.TAB_REPLACEMENT.toString()) - val indent = - getWhitespacePrefix(*textVar.split(TextBlock.DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray()) - return LineComment( - commentPrefix, - indent, - *Arrays.stream(textVar.split(TextBlock.DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray()) - .map { s: String? -> - stripPrefix( - s!!, indent - ) - } - .map { obj: CharSequence -> trimPrefix(obj) } - .map { s: CharSequence? -> - stripPrefix( - s!!, - commentPrefix - ) - } - .collect(Collectors.toList()).toTypedArray()) - } - - override fun looksLike(text: String?): Boolean { - return Arrays.stream(text!!.split(TextBlock.DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray()).allMatch { x: String -> - x.trim { it <= ' ' }.startsWith( - commentPrefix - ) - } - } - } - - override fun toString(): String { - return "$commentPrefix " + Arrays.stream(rawString()) - .collect(Collectors.joining(TextBlock.DELIMITER + indent + commentPrefix + " ")) - } - - override fun withIndent(indent: CharSequence): LineComment { - return LineComment(commentPrefix, indent, *lines) - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/PluginStartupActivity.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/PluginStartupActivity.kt deleted file mode 100644 index d7ae96a4..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/PluginStartupActivity.kt +++ /dev/null @@ -1,194 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.fileEditor.FileEditorManagerListener -import com.intellij.openapi.fileEditor.TextEditorWithPreview -import com.intellij.openapi.project.Project -import com.intellij.openapi.startup.ProjectActivity -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.openapi.vfs.VirtualFileManager -import com.simiacryptus.jopenai.models.ChatModel -import com.simiacryptus.skyenet.core.OutputInterceptor -import com.simiacryptus.skyenet.core.platform.* -import com.simiacryptus.skyenet.core.platform.hsql.HSQLUsageManager -import com.simiacryptus.skyenet.core.platform.model.ApplicationServicesConfig -import com.simiacryptus.skyenet.core.platform.model.ApplicationServicesConfig.isLocked -import com.simiacryptus.skyenet.core.platform.model.AuthenticationInterface -import com.simiacryptus.skyenet.core.platform.model.AuthorizationInterface -import com.simiacryptus.skyenet.core.platform.model.User -import org.jetbrains.annotations.NonNls -import software.amazon.awssdk.regions.Region -import java.io.File -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.reflect.full.declaredMembers -import kotlin.reflect.jvm.isAccessible - -class PluginStartupActivity : ProjectActivity { - private val documentationPageOpenTimes = ConcurrentHashMap() - private lateinit var messageBusConnection: com.intellij.util.messages.MessageBusConnection - override suspend fun execute(project: Project) { - // Check if this is the first run after installation - try { - //ApplicationServicesConfig.dataStorageRoot = ApplicationServicesConfig.dataStorageRoot.resolve("intellij") - val currentThread = Thread.currentThread() - val prevClassLoader = currentThread.contextClassLoader - try { - currentThread.contextClassLoader = PluginStartupActivity::class.java.classLoader - init() - // Add user-supplied models to ChatModel - addUserSuppliedModels(AppSettingsState.instance.userSuppliedModels) - } finally { - currentThread.contextClassLoader = prevClassLoader - } - // Set up file editor listener for documentation tracking - setupDocumentationTracking(project) - - if (AppSettingsState.instance.showWelcomeScreen || AppSettingsState.instance.greetedVersion != AppSettingsState.WELCOME_VERSION) { - val welcomeFile = "welcomePage.md" - val resource = PluginStartupActivity::class.java.classLoader.getResource(welcomeFile) - var virtualFile = resource?.let { VirtualFileManager.getInstance().findFileByUrl(it.toString()) } - if (virtualFile == null) try { - val path = resource?.toURI()?.let { java.nio.file.Paths.get(it) } - virtualFile = path?.let { VirtualFileManager.getInstance().findFileByNioPath(it) } - } catch (e: Exception) { - log.debug("Error opening welcome page", e) - } - if (virtualFile == null) { - try { - val tempFile = - File.createTempFile(welcomeFile.substringBefore("."), "." + welcomeFile.substringAfter(".")) - tempFile.deleteOnExit() - resource?.openStream()?.use { input -> - tempFile.outputStream().use { output -> input.copyTo(output) } - } - virtualFile = VirtualFileManager.getInstance().refreshAndFindFileByNioPath(tempFile.toPath()) - } catch (e: Exception) { - log.error("Error opening welcome page", e) - } - } - virtualFile?.let { - try { - ApplicationManager.getApplication().invokeLater { - FileEditorManager.getInstance(project).openFile(it, true).forEach { editor -> - try { - editor::class.declaredMembers.filter { it.name == "setLayout" }.forEach { member -> - member.isAccessible = true - member.call(editor, TextEditorWithPreview.Layout.SHOW_PREVIEW) - } - } catch (e: Exception) { - log.error("Error opening welcome page", e) - } - } - } - } catch (e: Exception) { - log.error("Error opening welcome page", e) - } - } ?: log.error("Welcome page not found") - // Set showWelcomeScreen to false after showing it for the first time - AppSettingsState.instance.greetedVersion = AppSettingsState.WELCOME_VERSION - AppSettingsState.instance.showWelcomeScreen = false - } - } catch (e: Exception) { - log.error("Error during plugin startup", e) - } - } - private fun setupDocumentationTracking(project: Project) { - messageBusConnection = project.messageBus.connect() - messageBusConnection.subscribe( - FileEditorManagerListener.FILE_EDITOR_MANAGER, - object : FileEditorManagerListener { - override fun fileOpened(source: FileEditorManager, file: VirtualFile) { - if (isDocumentationFile(file)) { - trackDocumentationPageView(file) - } - } - override fun fileClosed(source: FileEditorManager, file: VirtualFile) { - if (isDocumentationFile(file)) { - trackDocumentationPageClose(file) - } - } - } - ) - } - private fun isDocumentationFile(file: VirtualFile): Boolean { - return file.path.contains("/docs/") || file.extension == "md" - } - private fun trackDocumentationPageView(file: VirtualFile) { - if (AppSettingsState.instance.analyticsEnabled) { - val pagePath = file.path - documentationPageOpenTimes[pagePath] = System.currentTimeMillis() - mapOf("page" to pagePath) - } - } - private fun trackDocumentationPageClose(file: VirtualFile) { - if (AppSettingsState.instance.analyticsEnabled) { - val pagePath = file.path - val openTime = documentationPageOpenTimes.remove(pagePath) - if (openTime != null) { - val timeSpent = System.currentTimeMillis() - openTime - mapOf( - "page" to pagePath, - "time_spent" to TimeUnit.MILLISECONDS.toSeconds(timeSpent) - ) - } - } - } - - private val isInitialized = AtomicBoolean(false) - - private fun init() { - if (isInitialized.getAndSet(true)) return - ApplicationServicesConfig.dataStorageRoot = AppSettingsState.instance.pluginHome.resolve(".skyenet") - OutputInterceptor.setupInterceptor() - ApplicationServices.clientManager = object : ClientManager() { - override fun createChatClient(session: Session, user: User?) = - IdeaChatClient.instance - } - AppSettingsState.instance.apply { - if (!awsProfile.isNullOrBlank() && !awsRegion.isNullOrBlank() && !awsBucket.isNullOrBlank()) { - ApplicationServices.cloud = AwsPlatform( - bucket = awsBucket!!, - region = Region.of(awsRegion!!), - profileName = awsProfile!!, - ) - } else { - ApplicationServices.cloud = null - } - } - ApplicationServices.usageManager = HSQLUsageManager(ApplicationServicesConfig.dataStorageRoot.resolve("usage")) - ApplicationServices.authorizationManager = object : AuthorizationInterface { - override fun isAuthorized( - applicationClass: Class<*>?, - user: User?, - operationType: AuthorizationInterface.OperationType - ) = true - } - ApplicationServices.authenticationManager = object : AuthenticationInterface { - override fun getUser(accessToken: String?) = null - override fun putUser(accessToken: String, user: User) = user - override fun logout(accessToken: String, user: User) {} - } - isLocked = true - } - - companion object { - val log = org.slf4j.LoggerFactory.getLogger(PluginStartupActivity::class.java) - - fun addUserSuppliedModels(userModels: List) { - userModels.forEach { model -> - ChatModel.values[model.displayName] = ChatModel( - name = model.displayName, - modelName = model.modelId, - maxTotalTokens = 4096, // Default value, adjust as needed - provider = model.provider, - inputTokenPricePerK = 0.0, // Default value, adjust as needed - outputTokenPricePerK = 0.0 // Default value, adjust as needed - ) - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/TextBlock.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/TextBlock.kt deleted file mode 100644 index 0fc0119e..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/TextBlock.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import java.util.stream.Stream -import kotlin.streams.asStream - -interface TextBlock { - companion object { - val TAB_REPLACEMENT: CharSequence = " " - const val DELIMITER: String = "\n" - } - - fun rawString(): Array - - val textBlock: CharSequence - get() = rawString().joinToString(DELIMITER) - - fun withIndent(indent: CharSequence): TextBlock - - fun stream(): Stream = rawString().asSequence().asStream() -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/TextBlockFactory.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/TextBlockFactory.kt deleted file mode 100644 index 0b1dbb0c..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/TextBlockFactory.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -interface TextBlockFactory { - fun fromString(text: String?): T - - @Suppress("unused") - fun toString(text: T): CharSequence? { - return text.toString() - } - - fun looksLike(text: String?): Boolean -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/UITools.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/UITools.kt deleted file mode 100644 index cb3946f7..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/UITools.kt +++ /dev/null @@ -1,955 +0,0 @@ -package com.github.simiacryptus.aicoder.util - -import com.github.simiacryptus.aicoder.actions.generic.toFile -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.config.Name -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse -import com.google.common.util.concurrent.* -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.command.WriteCommandAction -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Document -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.progress.ProgressManager -import com.intellij.openapi.progress.Task -import com.intellij.openapi.progress.util.AbstractProgressIndicatorBase -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.ComboBox -import com.intellij.openapi.ui.DialogWrapper -import com.intellij.openapi.util.TextRange -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.ui.components.JBLabel -import com.intellij.ui.components.JBPasswordField -import com.intellij.ui.components.JBScrollPane -import com.intellij.ui.components.JBTextArea -import com.intellij.util.ui.FormBuilder -import com.simiacryptus.jopenai.OpenAIClient -import com.simiacryptus.jopenai.exceptions.ModerationException -import com.simiacryptus.jopenai.models.APIProvider -import org.jdesktop.swingx.JXButton -import org.slf4j.LoggerFactory -import java.awt.* -import java.awt.event.ComponentAdapter -import java.awt.event.ComponentEvent -import java.awt.event.WindowAdapter -import java.awt.event.WindowEvent -import java.beans.PropertyChangeEvent -import java.io.IOException -import java.io.PrintWriter -import java.io.StringWriter -import java.net.URI -import java.util.* -import java.util.concurrent.* -import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicReference -import java.util.function.Supplier -import javax.swing.* -import javax.swing.text.JTextComponent -import kotlin.math.max -import kotlin.reflect.KMutableProperty -import kotlin.reflect.KProperty1 -import kotlin.reflect.KVisibility -import kotlin.reflect.full.memberProperties -import kotlin.reflect.jvm.isAccessible -import kotlin.reflect.jvm.javaField -import kotlin.reflect.jvm.javaType - -object UITools { - val retry = WeakHashMap() - - private val log = LoggerFactory.getLogger(UITools::class.java) - private val threadFactory: ThreadFactory = ThreadFactoryBuilder().setNameFormat("API Thread %d").build() - private val pool: ListeningExecutorService by lazy { - MoreExecutors.listeningDecorator( - ThreadPoolExecutor( - /* corePoolSize = */ AppSettingsState.instance.apiThreads, - /* maximumPoolSize = */AppSettingsState.instance.apiThreads, - /* keepAliveTime = */ 0L, - /* unit = */ TimeUnit.MILLISECONDS, - /* workQueue = */ LinkedBlockingQueue(), - /* threadFactory = */ threadFactory, - /* handler = */ ThreadPoolExecutor.AbortPolicy() - ) - ) - } - private val scheduledPool: ListeningScheduledExecutorService by lazy { - MoreExecutors.listeningDecorator(ScheduledThreadPoolExecutor(1, threadFactory)) - } - private val errorLog = mutableListOf>() - private val actionLog = mutableListOf() - private val singleThreadPool = Executors.newSingleThreadExecutor() - - fun getRoot(e: AnActionEvent) : String { - return getSelectedFolder(e)?.toFile?.absolutePath ?: UITools.getSelectedFile(e)?.toFile?.parent ?: "" - } - - fun redoableTask( - event: AnActionEvent, - request: Supplier, - ) { - log.debug("Starting redoableTask with event: ${event}, request: ${request}") - Futures.addCallback(pool.submit { - request.get() - }, futureCallback(event, request), pool) - log.debug("Submitted redoableTask for execution") - } - - private fun futureCallback( - event: AnActionEvent, - request: Supplier, - ) = object : FutureCallback { - override fun onSuccess(undo: Runnable) { - val requiredData = event.getData(CommonDataKeys.EDITOR) ?: return - val document = requiredData.document - retry[document] = getRetry(event, request, undo) - } - - override fun onFailure(t: Throwable) { - error(log, "Error", t) - } - } - - fun getRetry( - event: AnActionEvent, - request: Supplier, - undo: Runnable, - ): Runnable = Runnable { - Futures.addCallback( - pool.submit { - WriteCommandAction.runWriteCommandAction(event.project) { undo.run() } - request.get() - }, futureCallback(event, request), pool - ) - } - - fun replaceString(document: Document, startOffset: Int, endOffset: Int, newText: CharSequence): Runnable { - log.debug("Invoking replaceString with startOffset: $startOffset, endOffset: $endOffset, newText: $newText") - val oldText: CharSequence = document.getText(TextRange(startOffset, endOffset)) - document.replaceString(startOffset, endOffset, newText) - logEdit( - String.format( - "FWD replaceString from %s to %s (%s->%s): %s", - startOffset, - endOffset, - endOffset - startOffset, - newText.length, - newText - ) - ) - return Runnable { - val verifyTxt = document.getText(TextRange(startOffset, startOffset + newText.length)) - log.debug("Verifying text after replaceString: expected: $newText, actual: $verifyTxt") - if (verifyTxt != newText) { - val msg = String.format( - "The text range from %d to %d does not match the expected text \"%s\" and is instead \"%s\"", - startOffset, - startOffset + newText.length, - newText, - verifyTxt - ) - log.error("Verification failed after replaceString: $msg") - throw IllegalStateException(msg) - } - document.replaceString(startOffset, startOffset + newText.length, oldText) - logEdit( - String.format( - "REV replaceString from %s to %s (%s->%s): %s", - startOffset, - startOffset + newText.length, - newText.length, - oldText.length, - oldText - ) - ) - } - } - - fun insertString(document: Document, startOffset: Int, newText: CharSequence): Runnable { - document.insertString(startOffset, newText) - logEdit(String.format("FWD insertString @ %s (%s): %s", startOffset, newText.length, newText)) - return Runnable { - val verifyTxt = document.getText(TextRange(startOffset, startOffset + newText.length)) - if (verifyTxt != newText) { - val message = String.format( - "The text range from %d to %d does not match the expected text \"%s\" and is instead \"%s\"", - startOffset, - startOffset + newText.length, - newText, - verifyTxt - ) - throw AssertionError(message) - } - document.deleteString(startOffset, startOffset + newText.length) - logEdit(String.format("REV deleteString from %s to %s", startOffset, startOffset + newText.length)) - } - } - - private fun logEdit(message: String) { - log.debug(message) - } - - @Suppress("unused") - fun deleteString(document: Document, startOffset: Int, endOffset: Int): Runnable { - val oldText: CharSequence = document.getText(TextRange(startOffset, endOffset)) - document.deleteString(startOffset, endOffset) - return Runnable { - document.insertString(startOffset, oldText) - logEdit(String.format("REV insertString @ %s (%s): %s", startOffset, oldText.length, oldText)) - } - } - - fun getIndent(caret: Caret?): CharSequence { - if (null == caret) return "" - val document = caret.editor.document - val documentText = document.text - val lineNumber = document.getLineNumber(caret.selectionStart) - val lines = documentText.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - if (lines.isEmpty()) return "" - return IndentedText.fromString(lines[max(lineNumber, 0).coerceAtMost(lines.size - 1)]).indent - } - - @Suppress("unused") - fun hasSelection(e: AnActionEvent): Boolean { - val caret = e.getData(CommonDataKeys.CARET) - return null != caret && caret.hasSelection() - } - - fun getIndent(event: AnActionEvent): CharSequence { - val caret = event.getData(CommonDataKeys.CARET) - val indent: CharSequence = if (null == caret) { - "" - } else { - getIndent(caret) - } - return indent - } - - fun readKotlinUIViaReflection(component: R, settings: T) { - val componentClass: Class<*> = component.javaClass - val declaredUIFields = componentClass.kotlin.memberProperties.map { it.name }.toSet() - for (settingsField in settings.javaClass.kotlin.memberProperties) { - if (settingsField is KMutableProperty<*>) { - settingsField.isAccessible = true - val settingsFieldName = settingsField.name - try { - var newSettingsValue: Any? = null - if (!declaredUIFields.contains(settingsFieldName)) continue - val uiField: KProperty1 = - (componentClass.kotlin.memberProperties.find { it.name == settingsFieldName } as KProperty1?)!! - var uiVal = uiField.get(component) - if (uiVal is JScrollPane) { - uiVal = uiVal.viewport.view - } - when (settingsField.returnType.javaType.typeName) { - "java.lang.String" -> if (uiVal is JTextComponent) { - newSettingsValue = uiVal.text - } else if (uiVal is ComboBox<*>) { - newSettingsValue = uiVal.item - } - - "int", "java.lang.Integer" -> if (uiVal is JTextComponent) { - newSettingsValue = if (uiVal.text.isBlank()) -1 else uiVal.text.toInt() - } - - "long" -> if (uiVal is JTextComponent) { - newSettingsValue = if (uiVal.text.isBlank()) -1 else uiVal.text.toLong() - } - - "double", "java.lang.Double" -> if (uiVal is JTextComponent) { - newSettingsValue = if (uiVal.text.isBlank()) 0.0 else uiVal.text.toDouble() - } - - "boolean" -> if (uiVal is JCheckBox) { - newSettingsValue = uiVal.isSelected - } else if (uiVal is JTextComponent) { - newSettingsValue = java.lang.Boolean.parseBoolean(uiVal.text) - } - - else -> if (Enum::class.java.isAssignableFrom(settingsField.returnType.javaType as Class<*>)) { - if (uiVal is ComboBox<*>) { - val comboBox = uiVal - val item = comboBox.item - val enumClass = settingsField.returnType.javaType as Class?> - val string = item.toString() - newSettingsValue = findValue(enumClass, string) - } - } - } - settingsField.setter.call(settings, newSettingsValue) - } catch (e: Throwable) { - throw RuntimeException("Error processing $settingsField", e) - } - } - } - } - - private fun findValue(enumClass: Class?>, string: String): Enum<*>? { - enumClass.enumConstants?.filter { it?.name?.compareTo(string, true) == 0 }?.forEach { return it } - return java.lang.Enum.valueOf( - enumClass, string - ) - } - - fun writeKotlinUIViaReflection(settings: T, component: R) { - val componentClass: Class<*> = component.javaClass - val declaredUIFields = componentClass.kotlin.memberProperties.map { it.name }.toSet() - val memberProperties = settings.javaClass.kotlin.memberProperties - val publicProperties = memberProperties.filter { - it.visibility == KVisibility.PUBLIC //&& it is KMutableProperty<*> - } - for (settingsField in publicProperties) { - val fieldName = settingsField.name - try { - if (!declaredUIFields.contains(fieldName)) { - log.warn("Field not found: $fieldName") - continue - } - val uiField: KProperty1 = - (componentClass.kotlin.memberProperties.find { it.name == fieldName } as KProperty1?)!! - val settingsVal = settingsField.get(settings) ?: continue - var uiVal = uiField.get(component) - if (uiVal is JScrollPane) { - uiVal = uiVal.viewport.view - } - when (settingsField.returnType.javaType.typeName) { - "java.lang.String" -> if (uiVal is JTextComponent) { - uiVal.text = settingsVal.toString() - } else if (uiVal is ComboBox<*>) { - (uiVal as ComboBox).item = settingsVal.toString() - } - - "int", "java.lang.Integer" -> if (uiVal is JTextComponent) { - uiVal.text = (settingsVal as Int).toString() - } - - "long" -> if (uiVal is JTextComponent) { - uiVal.text = (settingsVal as Int).toLong().toString() - } - - "boolean" -> if (uiVal is JCheckBox) { - uiVal.isSelected = (settingsVal as Boolean) - } else if (uiVal is JTextComponent) { - uiVal.text = java.lang.Boolean.toString((settingsVal as Boolean)) - } - - "double", "java.lang.Double" -> if (uiVal is JTextComponent) { - uiVal.text = (settingsVal as Double).toString() - } - - else -> if (uiVal is ComboBox<*>) { - (uiVal as ComboBox).item = settingsVal.toString() - } - } - } catch (e: Throwable) { - throw RuntimeException("Error processing $settingsField", e) - } - } - } - - private fun addKotlinFields(ui: T, formBuilder: FormBuilder, fillVertically: Boolean) { - var first = true - for (field in ui.javaClass.kotlin.memberProperties) { - if (field.javaField == null) continue - try { - val nameAnnotation = field.annotations.find { it is Name } as Name? - val component = field.get(ui) as JComponent - if (nameAnnotation != null) { - if (first && fillVertically) { - first = false - formBuilder.addLabeledComponentFillVertically(nameAnnotation.value + ": ", component) - } else { - formBuilder.addLabeledComponent(JBLabel(nameAnnotation.value + ": "), component, 1, false) - } - } else { - formBuilder.addComponentToRightColumn(component, 1) - } - } catch (e: IllegalAccessException) { - throw RuntimeException(e) - } catch (e: Throwable) { - error(log, "Error processing " + field.name, e) - } - } - } - - private fun getMaximumSize(factor: Double): Dimension { - val screenSize = Toolkit.getDefaultToolkit().screenSize - return Dimension((screenSize.getWidth() * factor).toInt(), (screenSize.getHeight() * factor).toInt()) - } - - private fun showOptionDialog(mainPanel: JPanel?, vararg options: Any, title: String, modal: Boolean = true): Int { - val pane = getOptionPane(mainPanel, options) - val rootFrame = JOptionPane.getRootFrame() - pane.componentOrientation = rootFrame.componentOrientation - val dialog = JDialog(rootFrame, title, modal) - dialog.componentOrientation = rootFrame.componentOrientation - - val latch = if (!modal) CountDownLatch(1) else null - configure(dialog, pane, latch) - dialog.isVisible = true - if (!modal) latch?.await() - - dialog.dispose() - return getSelectedValue(pane, options) - } - - private fun getOptionPane( - mainPanel: JPanel?, - options: Array, - ): JOptionPane { - val pane = JOptionPane( - mainPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.NO_OPTION, null, options, options[0] - ) - pane.initialValue = options[0] - return pane - } - - private fun configure(dialog: JDialog, pane: JOptionPane, latch: CountDownLatch? = null) { - val contentPane = dialog.contentPane - contentPane.layout = BorderLayout() - contentPane.add(pane, BorderLayout.CENTER) - - if (JDialog.isDefaultLookAndFeelDecorated() && UIManager.getLookAndFeel().supportsWindowDecorations) { - dialog.isUndecorated = true - pane.rootPane.windowDecorationStyle = JRootPane.PLAIN_DIALOG - } - dialog.isResizable = true - dialog.maximumSize = getMaximumSize(0.9) - dialog.pack() - dialog.setLocationRelativeTo(null as Component?) - val adapter: WindowAdapter = windowAdapter(pane, dialog) - dialog.addWindowListener(adapter) - dialog.addWindowFocusListener(adapter) - dialog.addComponentListener(object : ComponentAdapter() { - override fun componentShown(ce: ComponentEvent) { - // reset value to ensure closing works properly - pane.value = JOptionPane.UNINITIALIZED_VALUE - } - }) - pane.addPropertyChangeListener { event: PropertyChangeEvent -> - if (dialog.isVisible && event.source === pane && event.propertyName == JOptionPane.VALUE_PROPERTY && event.newValue != null && event.newValue !== JOptionPane.UNINITIALIZED_VALUE) { - dialog.isVisible = false - latch?.countDown() - } - } - - pane.selectInitialValue() - } - - private fun windowAdapter(pane: JOptionPane, dialog: JDialog): WindowAdapter { - val adapter: WindowAdapter = object : WindowAdapter() { - private var gotFocus = false - override fun windowClosing(we: WindowEvent) { - pane.value = null - } - - override fun windowClosed(e: WindowEvent) { - pane.removePropertyChangeListener { event: PropertyChangeEvent -> - if (dialog.isVisible && event.source === pane && event.propertyName == JOptionPane.VALUE_PROPERTY && event.newValue != null && event.newValue !== JOptionPane.UNINITIALIZED_VALUE) { - dialog.isVisible = false - } - } - dialog.contentPane.removeAll() - } - - override fun windowGainedFocus(we: WindowEvent) { - if (!gotFocus) { - pane.selectInitialValue() - gotFocus = true - } - } - } - return adapter - } - - private fun getSelectedValue(pane: JOptionPane, options: Array): Int { - val selectedValue = pane.value ?: return JOptionPane.CLOSED_OPTION - var counter = 0 - val maxCounter = options.size - while (counter < maxCounter) { - if (options[counter] == selectedValue) return counter - counter++ - } - return JOptionPane.CLOSED_OPTION - } - - private fun wrapScrollPane(promptArea: JBTextArea?): JBScrollPane { - val scrollPane = JBScrollPane(promptArea) - scrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - scrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED - return scrollPane - } - - fun showCheckboxDialog( - promptMessage: String, - checkboxIds: Array, - checkboxDescriptions: Array, - ): Array { - val formBuilder = FormBuilder.createFormBuilder() - val checkboxMap = HashMap() - for (i in checkboxIds.indices) { - val checkbox = JCheckBox(checkboxDescriptions[i], null as Icon?, true) - checkboxMap[checkboxIds[i]] = checkbox - formBuilder.addComponent(checkbox) - } - val dialogResult = showOptionDialog(formBuilder.panel, "OK", title = promptMessage) - val selectedIds = ArrayList() - if (dialogResult == 0) { - for ((checkboxId, checkbox) in checkboxMap) { - if (checkbox.isSelected) { - selectedIds.add(checkboxId) - } - } - } - return selectedIds.toTypedArray() - } - - fun showRadioButtonDialog( - promptMessage: CharSequence, - vararg radioButtonDescriptions: CharSequence, - ): CharSequence? { - val formBuilder = FormBuilder.createFormBuilder() - val radioButtonMap = HashMap() - val buttonGroup = ButtonGroup() - for (i in radioButtonDescriptions.indices) { - val radioButton = JRadioButton(radioButtonDescriptions[i].toString(), null as Icon?, true) - radioButtonMap[radioButtonDescriptions[i].toString()] = radioButton - buttonGroup.add(radioButton) - formBuilder.addComponent(radioButton) - } - val dialogResult = showOptionDialog(formBuilder.panel, "OK", title = promptMessage.toString()) - if (dialogResult == 0) { - for ((radioButtonId, radioButton) in radioButtonMap) { - if (radioButton.isSelected) { - return radioButtonId - } - } - } - return null - } - - fun buildFormViaReflection( - component: T, - fillVertically: Boolean = true, - formBuilder: FormBuilder = FormBuilder.createFormBuilder(), - ): JPanel? { - addKotlinFields(component, formBuilder, fillVertically) - return formBuilder.addComponentFillVertically(JPanel(), 0).panel - } - - fun showDialog( - project: Project?, - uiClass: Class, - configClass: Class, - title: String = "Generate Project", - onComplete: (C) -> Unit = { _ -> }, - ): C = showDialog( - project, - uiClass.getConstructor().newInstance(), - configClass.getConstructor().newInstance(), - title, - onComplete - ) - - fun showDialog( - project: Project?, - component: T, - config: C, - title: String, - onComplete: (C) -> Unit - ): C { - log.debug("Showing dialog with title: $title") - val dialog = object : DialogWrapper(project) { - init { - this.init() - this.title = title - this.setOKButtonText("Generate") - this.setCancelButtonText("Cancel") - this.isResizable = true - //this.setPreferredFocusedComponent(this) - //this.setContent(this) - } - - override fun createCenterPanel(): JComponent? { - log.debug("Creating center panel for dialog") - return buildFormViaReflection(component) - } - } - dialog.show() - log.debug("Dialog shown with result: ${dialog.isOK}") - if (dialog.isOK) { - readKotlinUIViaReflection(component, config) - log.debug("Reading UI via reflection completed") - onComplete(config) - log.debug("onComplete callback executed") - } - return config - } - - fun getSelectedFolder(e: AnActionEvent): VirtualFile? { - val dataContext = e.dataContext - val data = PlatformDataKeys.VIRTUAL_FILE.getData(dataContext) - if (data != null && data.isDirectory) { - return data - } - val editor = PlatformDataKeys.EDITOR.getData(dataContext) - if (editor != null) { - val file = FileDocumentManager.getInstance().getFile(editor.document) - if (file != null) { - return file.parent - } - } - return null - } - - fun getSelectedFile(e: AnActionEvent): VirtualFile? { - val dataContext = e.dataContext - val data = PlatformDataKeys.VIRTUAL_FILE.getData(dataContext) - if (data != null && !data.isDirectory) { - return data - } - val editor = PlatformDataKeys.EDITOR.getData(dataContext) - if (editor != null) { - val file = FileDocumentManager.getInstance().getFile(editor.document) - if (file != null) { - return file - } - } - return null - } - - fun getSelectedFiles(e: AnActionEvent): List { - val dataContext = e.dataContext - val data = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) - if (null != data) return data.toList() - val editor = PlatformDataKeys.EDITOR.getData(dataContext) - if (editor != null) { - val file = FileDocumentManager.getInstance().getFile(editor.document) - if (file != null) { return listOf(file) } - } - return emptyList() - } - - fun writeableFn( - event: AnActionEvent, - fn: () -> Runnable, - ): Runnable { - val runnable = AtomicReference() - WriteCommandAction.runWriteCommandAction(event.project) { runnable.set(fn()) } - return runnable.get() - } - - class ModalTask( - project: Project, title: String, canBeCancelled: Boolean, val task: (ProgressIndicator) -> T - ) : Task.WithResult(project, title, canBeCancelled), Supplier { - private val result = AtomicReference() - private val isError = AtomicBoolean(false) - private val error = AtomicReference() - private val semaphore = Semaphore(0) - override fun compute(indicator: ProgressIndicator): T? { - val currentThread = Thread.currentThread() - val threads = ArrayList() - val scheduledFuture = scheduledPool.scheduleAtFixedRate({ - if (indicator.isCanceled) { - threads.forEach { it.interrupt() } - } - }, 0, 1, TimeUnit.SECONDS) - threads.add(currentThread) - return try { - result.set(task(indicator)) - result.get() - } catch (e: Throwable) { - error(log, "Error running task", e) - isError.set(true) - error.set(e) - null - } finally { - semaphore.release() - threads.remove(currentThread) - scheduledFuture.cancel(true) - } - } - - override fun get(): T { - semaphore.acquire() - semaphore.release() - if (isError.get()) { - throw error.get() - } - return result.get() - } - - } - - class BgTask( - project: Project, title: String, canBeCancelled: Boolean, val task: (ProgressIndicator) -> T - ) : Task.Backgroundable(project, title, canBeCancelled, DEAF), Supplier { - - private val result = AtomicReference() - private val isError = AtomicBoolean(false) - private val error = AtomicReference() - private val semaphore = Semaphore(0) - override fun run(indicator: ProgressIndicator) { - val currentThread = Thread.currentThread() - val threads = ArrayList() - val scheduledFuture = scheduledPool.scheduleAtFixedRate({ - if (indicator.isCanceled) { - threads.forEach { it.interrupt() } - } - }, 0, 1, TimeUnit.SECONDS) - threads.add(currentThread) - try { - val result = task(indicator) - this.result.set(result) - } catch (e: Throwable) { - log.info("Error running task", e) - error.set(e) - isError.set(true) - } finally { - semaphore.release() - threads.remove(currentThread) - scheduledFuture.cancel(true) - } - } - - override fun get(): T { - semaphore.acquire() - semaphore.release() - if (isError.get()) { - throw error.get() - } - return result.get() - } - } - - fun run( - project: Project?, - title: String?, - canBeCancelled: Boolean = true, - suppressProgress: Boolean = true, - task: (ProgressIndicator) -> T, - ): T { - return if (project == null || suppressProgress == AppSettingsState.instance.editRequests) { - checkApiKey() - task(AbstractProgressIndicatorBase()) - } else { - checkApiKey() - val t = if (AppSettingsState.instance.modalTasks) ModalTask(project, title ?: "", canBeCancelled, task) - else BgTask(project, title ?: "", canBeCancelled, task) - ProgressManager.getInstance().run(t) - t.get() - } - } - - fun checkApiKey(k: String = AppSettingsState.instance.apiKey?.values?.firstOrNull() ?: ""): String { -// var key = k -// if (key.isEmpty() || key != AppSettingsState.instance.apiKey) { -// synchronized(OpenAIClient::class.java) { -// key = AppSettingsState.instance.apiKey -// if (key.isEmpty()) { -// key = queryAPIKey()?.toString() ?: "" -// if (key.isNotEmpty()) AppSettingsState.instance.apiKey = key -// } -// } -// } - return k - } - - - fun map( - moderateAsync: ListenableFuture, - o: com.google.common.base.Function, - ): ListenableFuture = Futures.transform(moderateAsync, o::apply, pool) - - - fun logAction(message: String) { - actionLog += message - } - - - fun error(log: org.slf4j.Logger, msg: String, e: Throwable) { - log.error(msg, e) - errorLog += Pair(msg, e) - singleThreadPool.submit { - if (AppSettingsState.instance.suppressErrors) { - return@submit - } else if (e.matches { ModerationException::class.java.isAssignableFrom(it.javaClass) }) { - JOptionPane.showMessageDialog( - null, e.message, "This request was rejected by OpenAI Moderation", JOptionPane.WARNING_MESSAGE - ) - } else if (e.matches { - java.lang.InterruptedException::class.java.isAssignableFrom(it.javaClass) && it.message?.contains( - "sleep interrupted" - ) == true - }) { - JOptionPane.showMessageDialog( - null, - "This request was cancelled by the user", - "User Cancelled Request", - JOptionPane.WARNING_MESSAGE - ) - } else if (e.matches { IOException::class.java.isAssignableFrom(it.javaClass) && it.message?.contains("Incorrect API key") == true }) { - - val formBuilder = FormBuilder.createFormBuilder() - - formBuilder.addLabeledComponent( - "Error", JLabel("The API key was rejected by the server.") - ) - - val apiKeyInput = JBPasswordField() - //bugReportTextArea.rows = 40 - apiKeyInput.columns = 80 - apiKeyInput.isEditable = true - //apiKeyInput.text = """""".trimMargin() - formBuilder.addLabeledComponent("API Key", apiKeyInput) - - val openAccountButton = JXButton("Open Account Page") - openAccountButton.addActionListener { - browse(URI("https://platform.openai.com/account/api-keys")) - } - formBuilder.addLabeledComponent("OpenAI Account", openAccountButton) - - val testButton = JXButton("Test Key") - testButton.addActionListener { - val apiKey = apiKeyInput.password.joinToString("") - try { - OpenAIClient( - key = mapOf( - APIProvider.OpenAI to apiKey - ) - ).listModels() - JOptionPane.showMessageDialog( - null, - "The API key was accepted by the server. The new value will be saved.", - "Success", - JOptionPane.INFORMATION_MESSAGE - ) - AppSettingsState.instance.apiKey = mapOf(APIProvider.OpenAI.name to apiKey).toMutableMap() - } catch (e: Exception) { - JOptionPane.showMessageDialog( - null, "The API key was rejected by the server.", "Failure", JOptionPane.WARNING_MESSAGE - ) - return@addActionListener - } - } - formBuilder.addLabeledComponent("Validation", testButton) - val showOptionDialog = showOptionDialog( - formBuilder.panel, "Dismiss", title = "Error", modal = true - ) - log.info("showOptionDialog = $showOptionDialog") - } else { - val formBuilder = FormBuilder.createFormBuilder() - - formBuilder.addLabeledComponent( - "Error", - JLabel("Oops! Something went wrong. An error report has been generated. You can copy and paste the report below into a new issue on our Github page.") - ) - - val bugReportTextArea = JBTextArea() - bugReportTextArea.rows = 40 - bugReportTextArea.columns = 80 - bugReportTextArea.isEditable = false - bugReportTextArea.text = """ - |Log Message: $msg - |Error Message: ${e.message} - |Error Type: ${e.javaClass.name} - |API Base: ${AppSettingsState.instance.apiBase} - | - |OS: ${System.getProperty("os.name")} / ${System.getProperty("os.version")} / ${System.getProperty("os.arch")} - |Locale: ${Locale.getDefault().country} / ${Locale.getDefault().language} - | - |Error Details: - |``` - |${toString(e)/*.indent(" ")*/} - |``` - | - |Action History: - | - |${actionLog.joinToString("\n") { "* ${it.replace("\n", "\n ")}" }} - | - |Error History: - | - |${ - errorLog.filter { it.second != e }.joinToString("\n") { - """ - |${it.first} - |``` - |${toString(it.second)/*.indent(" ")*/} - |``` - |""".trimMargin() - } - } - |""".trimMargin() - formBuilder.addLabeledComponent("System Report", wrapScrollPane(bugReportTextArea)) - - val openButton = JXButton("Open New Issue on our Github page") - openButton.addActionListener { - browse(URI("https://github.com/SimiaCryptus/intellij-aicoder/issues/new")) - } - formBuilder.addLabeledComponent("Report Issue/Request Help", openButton) - - val supressFutureErrors = JCheckBox("Suppress Future Error Popups") - supressFutureErrors.isSelected = false - formBuilder.addComponent(supressFutureErrors) - - val showOptionDialog = showOptionDialog( - formBuilder.panel, "Dismiss", title = "Error", modal = true - ) - log.info("showOptionDialog = $showOptionDialog") - if (supressFutureErrors.isSelected) { - AppSettingsState.instance.suppressErrors = true - } - } - } - } - - private fun Throwable.matches(matchFn: (Throwable) -> Boolean): Boolean { - if (matchFn(this)) return true - if (this.cause != null && this.cause !== this) return this.cause!!.matches(matchFn) - return false - } - - fun Throwable.get(matchFn: (Throwable) -> Boolean): Throwable? { - if (matchFn(this)) return this - if (this.cause != null && this.cause !== this) return this.cause!!.get(matchFn) - return null - } - - fun toString(e: Throwable): String { - val sw = StringWriter() - val pw = PrintWriter(sw) - e.printStackTrace(pw) - return sw.toString() - } - - fun showInputDialog( - parentComponent: Component?, message: Any?, title: String?, messageType: Int - ): Any? { - val icon = null - val selectionValues = null - val initialSelectionValue = null - val pane = JOptionPane( - message, messageType, JOptionPane.OK_CANCEL_OPTION, icon, null, null - ) - pane.wantsInput = true - pane.selectionValues = selectionValues - pane.initialSelectionValue = initialSelectionValue - //pane.isComponentOrientationLeftToRight = true - val dialog = pane.createDialog(parentComponent, title) - pane.selectInitialValue() - dialog.isVisible = true - dialog.dispose() - val value = pane.inputValue - return if (value == JOptionPane.UNINITIALIZED_VALUE) null else value - } - - fun showErrorDialog(project: Project?, errorMessage: String, subMessage: String) { - val formBuilder = FormBuilder.createFormBuilder() - formBuilder.addLabeledComponent("Error", JLabel(errorMessage)) - formBuilder.addLabeledComponent("Details", JLabel(subMessage)) - showOptionDialog(formBuilder.panel, "Dismiss", title = "Error", modal = true) - } - -} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiClassContext.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiClassContext.kt deleted file mode 100644 index 2935a5a5..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiClassContext.kt +++ /dev/null @@ -1,151 +0,0 @@ -package com.github.simiacryptus.aicoder.util.psi - -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiElementVisitor -import com.intellij.psi.PsiFile - -class PsiClassContext( - val text: String, - private val isPrior: Boolean, - private val isOverlap: Boolean, - val language: ComputerLanguage -) { - val children = ArrayList() - - /** - * This java code is initializing a PsiClassContext object. It is doing this by creating a PsiElementVisitor and using it to traverse the PsiFile. - * It is checking the text range of each element and whether it is prior to, overlapping, or within the selectionStart and selectionEnd parameters. - * Depending on the element, it is adding the text of the element to the PsiClassContext object, or recursively visiting its children. - * - * @param psiFile - * @param selectionStart - * @param selectionEnd - * @return - */ - fun init(psiFile: PsiFile?, selectionStart: Int, selectionEnd: Int): PsiClassContext { - object : PsiVisitorBase() { - var currentContext = this@PsiClassContext - var indent = "" - override fun visit(element: PsiElement, self: PsiElementVisitor) { - val text = element.text - val textRange = element.textRange - val textRangeEndOffset = textRange.endOffset + 1 - val textRangeStartOffset = textRange.startOffset - // Check if the element comes before the selection - val isPrior = textRangeEndOffset < selectionStart - // Check if the element overlaps with the selection - val isOverlap = - textRangeStartOffset in selectionStart..selectionEnd || textRangeEndOffset in selectionStart..selectionEnd || selectionStart in textRangeStartOffset..textRangeEndOffset || selectionEnd in textRangeStartOffset..textRangeEndOffset - // Check if the element is within the selection - val within = - selectionStart in textRangeStartOffset until textRangeEndOffset && textRangeStartOffset <= selectionEnd && textRangeEndOffset > selectionEnd - if (PsiUtil.matchesType(element, "ImportList")) { - currentContext.children.add(PsiClassContext(text.trim { it <= ' ' }, isPrior, isOverlap, language)) - } else if (PsiUtil.matchesType(element, "Comment", "DocComment")) { - if (within) { - currentContext.children.add( - PsiClassContext( - indent + text.trim { it <= ' ' }, - false, - true, - language - ) - ) - } - } else if (PsiUtil.matchesType(element, "Field")) { - processChildren( - element, - self, - isPrior, - isOverlap, - indent + PsiUtil.getDeclaration(element).trim { it <= ' ' } + if (isOverlap) " {" else ";") - } else if (PsiUtil.matchesType(element, "Method", "Function", "FunctionDefinition", "Constructor")) { - val methodTerminator = when (language) { - ComputerLanguage.Java -> " { /* ... */}" - ComputerLanguage.Kotlin -> " { /* ... */}" - ComputerLanguage.Scala -> " { /* ... */}" - else -> ";" - } - processChildren( - element, - self, - isPrior, - isOverlap, - indent + PsiUtil.getDeclaration(element) - .trim { it <= ' ' } + (if (isOverlap) " {" else methodTerminator)) - } else if (PsiUtil.matchesType(element, "LocalVariable")) { - currentContext.children.add(PsiClassContext(indent + text.trim { it <= ' ' } + ";", - isPrior, - isOverlap, - language)) - } else if (PsiUtil.matchesType(element, "Class")) { - processChildren( - element, - self, - isPrior, - isOverlap, - indent + text.substring(0, text.indexOf('{')).trim { it <= ' ' } + " {") - if (!isOverlap) { - currentContext.children.add(PsiClassContext("}", isPrior, false, language)) - } - } else if (!isOverlap && PsiUtil.matchesType(element, "CodeBlock", "ForStatement")) { - // Skip - } else { - element.acceptChildren(self) - } - } - - private fun processChildren( - element: PsiElement, - self: PsiElementVisitor, - isPrior: Boolean, - isOverlap: Boolean, - declarationText: String - ): PsiClassContext { - val newNode = PsiClassContext(declarationText, isPrior, isOverlap, language) - currentContext.children.add(newNode) - val prevclassBuffer = currentContext - currentContext = newNode - val prevIndent = indent - indent += " " - element.acceptChildren(self) - indent = prevIndent - currentContext = prevclassBuffer - return newNode - } - }.build(psiFile!!) - return this - } - - override fun toString(): String { - val sb = ArrayList() - sb.add(text) - children.stream().filter { x: PsiClassContext -> x.isPrior }.map { obj: PsiClassContext -> obj.toString() } - .forEach { e: String -> sb.add(e) } - children.stream().filter { x: PsiClassContext -> !x.isOverlap && !x.isPrior } - .map { obj: PsiClassContext -> obj.toString() } - .forEach { e: String -> sb.add(e) } - children.stream().filter { x: PsiClassContext -> x.isOverlap }.map { obj: PsiClassContext -> obj.toString() } - .forEach { e: String -> sb.add(e) } - return sb.stream().reduce { l: String, r: String -> - """ - $l - $r - """.trimIndent() - }.get() - } - - companion object { - @JvmStatic - fun getContext( - psiFile: PsiFile?, - selectionStart: Int, - selectionEnd: Int, - language: ComputerLanguage - ): PsiClassContext { - return PsiClassContext("", false, true, language).init(psiFile, selectionStart, selectionEnd) - } - - } -} diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiUtil.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiUtil.kt deleted file mode 100644 index bf8d0ffd..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiUtil.kt +++ /dev/null @@ -1,257 +0,0 @@ -package com.github.simiacryptus.aicoder.util.psi - -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiElementVisitor -import com.simiacryptus.util.StringUtil -import java.util.* -import java.util.concurrent.atomic.AtomicReference -import java.util.stream.Collectors -import java.util.stream.Stream - -object PsiUtil { - @JvmStatic - val ELEMENTS_CODE = arrayOf( - "Method", - "Field", - "Class", - "Function", - "CssBlock", - "FunctionDefinition" - ) - - @JvmStatic - val ELEMENTS_COMMENTS = arrayOf( - "Comment" - ) - - fun getAll(element: PsiElement, vararg types: CharSequence): List { - val elements: MutableList = ArrayList() - val visitor = AtomicReference() - visitor.set(object : PsiElementVisitor() { - override fun visitElement(element: PsiElement) { - if (matchesType(element, *types)) { - elements.add(element) - } else { - element.acceptChildren(visitor.get()) - } - super.visitElement(element) - } - }) - element.accept(visitor.get()) - return elements - } - - @JvmStatic - fun getSmallestIntersecting( - element: PsiElement, - selectionStart: Int, - selectionEnd: Int, - vararg types: CharSequence - ): PsiElement? { - val largest = AtomicReference(null) - val visitor = AtomicReference() - visitor.set(object : PsiElementVisitor() { - override fun visitElement(element: PsiElement) { - val textRange = element.textRange - if (intersects(TextRange(selectionStart, selectionEnd), textRange)) { - if (matchesType(element, *types)) { - largest.updateAndGet { s: PsiElement? -> - if ((s?.text?.length ?: Int.MAX_VALUE) < element.text.length) s else element - } - } - } - //System.out.printf("%s : %s%n", simpleName, element.getText()); - super.visitElement(element) - element.acceptChildren(visitor.get()) - } - }) - element.accept(visitor.get()) - return largest.get() - } - - @JvmStatic - private fun within(textRange: TextRange, vararg offset: Int): Boolean = - offset.any { it in textRange.startOffset..textRange.endOffset } - - private fun intersects(a: TextRange, b: TextRange): Boolean { - return within(a, b.startOffset, b.endOffset) || within(b, a.startOffset, a.endOffset) - } - - - @JvmStatic - fun matchesType(element: PsiElement, vararg types: CharSequence): Boolean { - return matchesType(element.javaClass.simpleName, types) - } - - @JvmStatic - fun matchesType(simpleName: CharSequence, types: Array): Boolean { - var simpleName1 = simpleName - simpleName1 = StringUtil.stripSuffix(simpleName1, "Impl") - simpleName1 = StringUtil.stripPrefix(simpleName1, "Psi") - val str = simpleName1.toString() - return Stream.of(*types) - .map { s: CharSequence? -> - StringUtil.stripSuffix( - s!!, "Impl" - ) - } - .map { s: String? -> - StringUtil.stripPrefix( - s!!, "Psi" - ) - } - .anyMatch { t: CharSequence -> str.endsWith(t.toString()) } - } - - @JvmStatic - private fun getFirstBlock(element: PsiElement, vararg blockType: CharSequence): PsiElement? { - val children = element.children - if (children.isEmpty()) return null - val first = children[0] - return if (matchesType(first, *blockType)) first else null - } - - @JvmStatic - private fun getLargestBlock(element: PsiElement, vararg blockType: CharSequence): PsiElement? { - val largest = AtomicReference(null) - val visitor = AtomicReference() - visitor.set(object : PsiElementVisitor() { - override fun visitElement(element: PsiElement) { - if (matchesType(element, *blockType)) { - largest.updateAndGet { s: PsiElement? -> if (s != null && s.text.length > element.text.length) s else element } - super.visitElement(element) - } else { - super.visitElement(element) - } - element.acceptChildren(visitor.get()) - } - }) - element.accept(visitor.get()) - return largest.get() - } - - fun printTree(element: PsiElement): String { - val builder = StringBuilder() - printTree(element, builder, 0) - return builder.toString() - } - - private fun printTree(element: PsiElement, builder: StringBuilder, level: Int) { - builder.append(" ".repeat(0.coerceAtLeast(level))) - val elementClass: Class = element.javaClass - val simpleName = getName(elementClass) - builder.append(simpleName).append(" ").append(element.text.replace("\n".toRegex(), "\\\\n")) - builder.append("\n") - for (child in element.children) { - printTree(child, builder, level + 1) - } - } - - private fun getName(elementClass: Class<*>): String { - var elementClassVar = elementClass - val stringBuilder = StringBuilder() - val interfaces = getInterfaces(elementClassVar) - while (elementClassVar != Any::class.java) { - if (stringBuilder.isNotEmpty()) stringBuilder.append("/") - stringBuilder.append(elementClassVar.simpleName) - elementClassVar = elementClassVar.superclass - } - stringBuilder.append("[ ") - stringBuilder.append(interfaces.stream().sorted().collect(Collectors.joining(","))) - stringBuilder.append("]") - return stringBuilder.toString() - } - - @JvmStatic - private fun getInterfaces(elementClass: Class<*>): Set { - val strings = Arrays.stream(elementClass.interfaces).map { obj: Class<*> -> obj.simpleName } - .collect( - Collectors.toCollection { HashSet() } - ) - if (elementClass.superclass != Any::class.java) strings.addAll(getInterfaces(elementClass.superclass)) - return strings - } - - @JvmStatic - private fun getLargestContainedEntity(element: PsiElement?, selectionStart: Int, selectionEnd: Int): PsiElement? { - if (null == element) return null - val textRange = element.textRange - if (textRange.startOffset >= selectionStart && textRange.endOffset <= selectionEnd) return element - var largestContainedChild: PsiElement? = null - for (child in element.children) { - val entity = getLargestContainedEntity(child, selectionStart, selectionEnd) - if (null != entity) { - if (largestContainedChild == null || largestContainedChild.textRange.length < entity.textRange.length) { - largestContainedChild = entity - } - } - } - return largestContainedChild - } - - @JvmStatic - fun getLargestContainedEntity(e: AnActionEvent): PsiElement? { - val caret = e.getData(CommonDataKeys.CARET) - ?: return null - var psiFile: PsiElement? = e.getData(CommonDataKeys.PSI_FILE) - ?: return null - val selectionStart = caret.selectionStart - val selectionEnd = caret.selectionEnd - val largestContainedEntity = getLargestContainedEntity(psiFile, selectionStart, selectionEnd) - if (largestContainedEntity != null) psiFile = largestContainedEntity - return psiFile - } - - @JvmStatic - fun getCodeElement( - psiFile: PsiElement?, - selectionStart: Int, - selectionEnd: Int - ) = getSmallestIntersecting(psiFile!!, selectionStart.toInt(), selectionEnd.toInt(), *ELEMENTS_CODE) - - @JvmStatic - fun getDeclaration(element: PsiElement): String { - var declaration: CharSequence = element.text - declaration = StringUtil.stripPrefix(declaration.toString().trim { it <= ' ' }, - getDocComment(element).trim { it <= ' ' }) - declaration = - StringUtil.stripSuffix(declaration.toString().trim { it <= ' ' }, getCode(element).trim { it <= ' ' }) - return declaration.toString().trim { it <= ' ' } - } - - @JvmStatic - fun getCode(element: PsiElement): String { - val codeBlock = getLargestBlock( - element, - "CodeBlock", - "BlockExpr", - "Block", - "BlockExpression", - "StatementList", - "BlockFields" - ) - var code = "" - if (null != codeBlock) { - code = codeBlock.text - } - return code - } - - @JvmStatic - fun getDocComment(element: PsiElement): String { - var docComment = getLargestBlock(element, "DocComment") - if (null == docComment) docComment = getFirstBlock(element, "Comment") - var prefix = "" - if (null != docComment) { - prefix = docComment.text.trim { it <= ' ' } - } - return prefix - } - -} - - - diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiVisitorBase.kt b/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiVisitorBase.kt deleted file mode 100644 index f2ddd63f..00000000 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/util/psi/PsiVisitorBase.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.github.simiacryptus.aicoder.util.psi - -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiElementVisitor -import com.intellij.psi.PsiFile -import java.util.concurrent.atomic.AtomicReference - -abstract class PsiVisitorBase { - fun build(psiFile: PsiFile) { - val visitor = AtomicReference() - visitor.set(object : PsiElementVisitor() { - override fun visitElement(element: PsiElement) { - visit(element, visitor.get()) - super.visitElement(element) - } - }) - psiFile.accept(visitor.get()) - } - - protected abstract fun visit(element: PsiElement, self: PsiElementVisitor) -} diff --git a/src/main/kotlin/com/simiacryptus/aicoder/AppServer.kt b/src/main/kotlin/com/simiacryptus/aicoder/AppServer.kt new file mode 100644 index 00000000..8e100d89 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/AppServer.kt @@ -0,0 +1,79 @@ +package com.simiacryptus.aicoder + +import aicoder.actions.SessionProxyServer +import com.intellij.openapi.project.Project +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.skyenet.webui.chat.ChatServer +import com.simiacryptus.skyenet.webui.servlet.CorsFilter +import jakarta.servlet.DispatcherType +import org.eclipse.jetty.server.Server +import org.eclipse.jetty.server.handler.ContextHandlerCollection +import org.eclipse.jetty.servlet.FilterHolder +import org.eclipse.jetty.webapp.WebAppContext +import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer +import org.slf4j.LoggerFactory +import java.net.InetSocketAddress +import java.util.* + +class AppServer( + private val localName: String, + private val port: Int +) { + + private val log by lazy { LoggerFactory.getLogger(javaClass) } + + val server by lazy { + val server = Server(InetSocketAddress(localName, port)) + server.handler = contexts + server + } + + private val handlers = arrayOf( + newWebAppContext(SessionProxyServer(), "/") + ).map { + it.addFilter(FilterHolder(CorsFilter()), "/*", EnumSet.of(DispatcherType.REQUEST)) + it + }.toMutableList() + + private val contexts by lazy { + val contexts = ContextHandlerCollection() + contexts.handlers = handlers.toTypedArray() + contexts + } + + private fun newWebAppContext(server: ChatServer, path: String): WebAppContext { + val context = WebAppContext() + JettyWebSocketServletContainerInitializer.configure(context, null) + context.baseResource = server.baseResource + context.classLoader = AppServer::class.java.classLoader + context.contextPath = path + context.welcomeFiles = arrayOf("index.html") + server.configure(context) + return context + } + + fun start() { + server.start() + } + + companion object { + @Transient + private var server: AppServer? = null + fun isRunning(): Boolean { + return server?.server?.isRunning ?: false + } + + fun getServer(project: Project?): AppServer { + if (null == server || !server!!.server.isRunning) { + server = AppServer( + AppSettingsState.instance.listeningEndpoint, + AppSettingsState.instance.listeningPort + ) + server!!.start() + } + return server!! + } + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/config/AppSettingsComponent.kt b/src/main/kotlin/com/simiacryptus/aicoder/config/AppSettingsComponent.kt new file mode 100644 index 00000000..79032179 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/config/AppSettingsComponent.kt @@ -0,0 +1,414 @@ +package com.simiacryptus.aicoder.config + + +import aicoder.actions.plan.PlanConfigDialog.Companion.isVisible +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileChooser.FileChooser +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.OpenFileDescriptor +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ProjectManager +import com.intellij.openapi.ui.ComboBox +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.ui.SimpleListCellRenderer +import com.intellij.ui.components.JBCheckBox +import com.intellij.ui.components.JBList +import com.intellij.ui.components.JBTextField +import com.intellij.ui.table.JBTable +import com.simiacryptus.aicoder.util.IdeaChatClient +import com.simiacryptus.jopenai.models.APIProvider +import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.jopenai.models.ImageModels +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import java.awt.BorderLayout +import java.awt.Dimension +import java.awt.event.ActionEvent +import java.io.FileOutputStream +import javax.swing.* +import javax.swing.event.ListSelectionEvent +import javax.swing.event.ListSelectionListener +import javax.swing.table.DefaultTableCellRenderer +import javax.swing.table.DefaultTableModel + +class AppSettingsComponent : com.intellij.openapi.Disposable { + @Suppress("unused") + @Name("GitHub Token") + val githubToken = JBTextField().apply { + toolTipText = "GitHub Personal Access Token" + columns = 30 + } + + @Suppress("unused") + @Name("Google API Key") + val googleApiKey = JBTextField().apply { + toolTipText = "Google API Key" + columns = 30 + } + + @Suppress("unused") + @Name("Google Search Engine ID") + val googleSearchEngineId = JBTextField().apply { + toolTipText = "Google Search Engine ID" + columns = 30 + } + + @Suppress("unused") + @Name("AWS Profile") + val awsProfile = JBTextField().apply { + toolTipText = "AWS Profile" + columns = 30 + } + + @Suppress("unused") + @Name("AWS Region") + val awsRegion = JBTextField().apply { + toolTipText = "AWS Region" + columns = 30 + } + + @Suppress("unused") + @Name("AWS Bucket") + val awsBucket = JBTextField().apply { + toolTipText = "AWS Bucket" + columns = 30 + } + + @Suppress("unused") + @Name("Store Metadata") + val storeMetadata = JTextArea().apply { + lineWrap = true + wrapStyleWord = true + } + + val executablesModel = DefaultListModel().apply { + AppSettingsState.instance.executables.forEach { addElement(it) } + } + val executablesList = JBList(executablesModel) + + @Suppress("unused") + @Name("Executables") + val executablesPanel = JPanel(BorderLayout()).apply { + val scrollPane = JScrollPane(executablesList) + scrollPane.preferredSize = Dimension(300, 200) + add(scrollPane, BorderLayout.CENTER) + val buttonPanel = JPanel() + val addButton = JButton("Add") + val removeButton = JButton("Remove") + val editButton = JButton("Edit") + removeButton.isEnabled = false + editButton.isEnabled = false + + addButton.addActionListener { + val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor() + descriptor.title = "Select Executable" + FileChooser.chooseFile(descriptor, null, null) { file -> + val executablePath = file.path + if (executablePath.isNotBlank() && !executablesModel.contains(executablePath)) { + executablesModel.addElement(executablePath) + AppSettingsState.instance.executables.add(executablePath) + } + } + } + removeButton.addActionListener { + val selectedIndices = executablesList.selectedIndices + for (i in selectedIndices.reversed()) { + val removed = executablesModel.remove(i) + AppSettingsState.instance.executables.remove(removed) + } + } + editButton.addActionListener { + val selectedIndex = executablesList.selectedIndex + if (selectedIndex != -1) { + val currentValue = executablesModel.get(selectedIndex) + val newValue = JOptionPane.showInputDialog(this, "Edit executable path:", currentValue) + if (newValue != null && newValue.isNotBlank()) { + executablesModel.set(selectedIndex, newValue) + AppSettingsState.instance.executables.remove(currentValue) + AppSettingsState.instance.executables.add(newValue) + } + } + } + executablesList.addListSelectionListener(object : ListSelectionListener { + override fun valueChanged(e: ListSelectionEvent?) { + val hasSelection = executablesList.selectedIndex != -1 + removeButton.isEnabled = hasSelection + editButton.isEnabled = hasSelection + } + }) + buttonPanel.add(addButton) + buttonPanel.add(removeButton) + buttonPanel.add(editButton) + add(buttonPanel, BorderLayout.SOUTH) + // Enable multiple selection for the list + executablesList.selectionMode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + } + + @Suppress("unused") + @Name("Human Language") + val humanLanguage = JBTextField() + + @Suppress("unused") + @Name("Listening Port") + val listeningPort = JBTextField() + + @Suppress("unused") + @Name("Listening Endpoint") + val listeningEndpoint = JBTextField() + + @Suppress("unused") + @Name("Suppress Errors") + val suppressErrors = JBCheckBox() + + @Suppress("unused") + @Name("Model") + val smartModel = ComboBox() + + @Suppress("unused") + @Name("Model") + val fastModel = ComboBox() + + @Suppress("unused") + @Name("Main Image Model") + val mainImageModel = ComboBox() + + @Suppress("unused") + @Name("Enable API Log") + val apiLog = JBCheckBox() + + @Suppress("unused") + val openApiLog = JButton(object : AbstractAction("Open API Log") { + override fun actionPerformed(e: ActionEvent) { + AppSettingsState.auxiliaryLog?.let { + if (it.exists()) { + val project = ApplicationManager.getApplication().runReadAction { + ProjectManager.getInstance().openProjects.firstOrNull() + } + ApplicationManager.getApplication().invokeLater { + val virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(it) + val openFileDescriptor = OpenFileDescriptor(project, virtualFile!!, virtualFile.length.toInt()) + FileEditorManager.getInstance(project!!) + .openTextEditor(openFileDescriptor, true)?.document?.setReadOnly( + true + ) + } + } + } + } + }) + + + @Suppress("unused") + val clearApiLog = JButton(object : AbstractAction("Clear API Log") { + override fun actionPerformed(e: ActionEvent) { + val openAIClient = IdeaChatClient.instance + openAIClient.logStreams.retainAll { it.close(); false } + AppSettingsState.auxiliaryLog?.let { + if (it.exists()) { + it.delete() + } + openAIClient.logStreams.add(FileOutputStream(it, true).buffered()) + } + } + }) + + + @Suppress("unused") + @Name("Developer Tools") + val devActions = JBCheckBox() + + @Suppress("unused") + @Name("Edit API Requests") + val editRequests = JBCheckBox() + + @Suppress("unused") + @Name("Disable Auto-Open URLs") + val disableAutoOpenUrls = JBCheckBox() + + + @Suppress("unused") + @Name("Plugin Home") + val pluginHome = JBTextField() + + @Suppress("unused") + val choosePluginHome = com.intellij.openapi.ui.TextFieldWithBrowseButton(pluginHome).apply { + val descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor() + val browserDescriptor = com.intellij.openapi.ui.ComponentWithBrowseButton.BrowseFolderActionListener( + "Select Plugin Home Directory", + null, + this, + null, + descriptor, + com.intellij.openapi.ui.TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT + ) + addActionListener(browserDescriptor) + } + + @Suppress("unused") + @Name("Shell Command") + val shellCommand = JBTextField() + + @Suppress("unused") + @Name("Show Welcome Screen") + val showWelcomeScreen = JBCheckBox("Show Welcome Screen", true) + + @Suppress("unused") + @Name("Enable Legacy Actions") + val enableLegacyActions = JBCheckBox() + + @Suppress("unused") + @Name("Temperature") + val temperature = JBTextField() + + @Name("APIs") + val apis = JBTable(DefaultTableModel(arrayOf("Provider", "Key", "Base URL"), 0)).apply { + columnModel.getColumn(0).preferredWidth = 100 + columnModel.getColumn(1).preferredWidth = 200 + columnModel.getColumn(2).preferredWidth = 200 + val keyColumnIndex = 1 + columnModel.getColumn(keyColumnIndex).cellRenderer = object : DefaultTableCellRenderer() { + override fun setValue(value: Any?) { + text = + if (value is String && value.isNotEmpty()) value.map { '*' }.joinToString("") else value?.toString() + ?: "" + } + } + } + + @Name("User-Supplied Models") + val userSuppliedModels = JBTable(DefaultTableModel(arrayOf("Display Name", "Model ID", "Provider"), 0)).apply { + columnModel.getColumn(0).preferredWidth = 150 + columnModel.getColumn(1).preferredWidth = 200 + columnModel.getColumn(2).preferredWidth = 100 + columnModel.getColumn(2).cellEditor = DefaultCellEditor(JComboBox(APIProvider.values().map { it.name }.toTypedArray())) + } + val addUserModelButton = JButton("Add Model").apply { + addActionListener { + (userSuppliedModels.model as DefaultTableModel).addRow(arrayOf("", "", APIProvider.OpenAI)) + } + } + val removeUserModelButton = JButton("Remove Model").apply { + addActionListener { + if (userSuppliedModels.selectedRow != -1) + (userSuppliedModels.model as DefaultTableModel).removeRow(userSuppliedModels.selectedRow) + } + } + + + @Name("Editor Actions") + var usage = UsageTable(ApplicationServices.usageManager) + fun getUserSuppliedModels(): List { + return (0 until userSuppliedModels.rowCount).map { row -> + AppSettingsState.UserSuppliedModel( + userSuppliedModels.getValueAt(row, 0) as String, + userSuppliedModels.getValueAt(row, 1) as String, + userSuppliedModels.getValueAt(row, 2) as APIProvider + ) + } + } + + fun setUserSuppliedModels(models: List) { + val model = userSuppliedModels.model as DefaultTableModel + model.rowCount = 0 + models.forEach { model.addRow(arrayOf(it.displayName, it.modelId, it.provider)) } + } + + init { + // Initialize new fields + githubToken.text = AppSettingsState.instance.githubToken ?: "" + googleApiKey.text = AppSettingsState.instance.googleApiKey ?: "" + googleSearchEngineId.text = AppSettingsState.instance.googleSearchEngineId ?: "" + awsProfile.text = AppSettingsState.instance.awsProfile ?: "" + awsRegion.text = AppSettingsState.instance.awsRegion ?: "" + awsBucket.text = AppSettingsState.instance.awsBucket ?: "" + disableAutoOpenUrls.isSelected = AppSettingsState.instance.disableAutoOpenUrls + // Initialize executables list + setExecutables(AppSettingsState.instance.executables) + ChatModel.values() + .filter { + AppSettingsState.instance.apiKey?.filter { it.value.isNotBlank() }?.keys?.contains(it.value.provider.name) + ?: false + } + .forEach { + this.smartModel.addItem(it.value.modelName) + this.fastModel.addItem(it.value.modelName) + } + ImageModels.values().forEach { + this.mainImageModel.addItem(it.name) + } + // Sort the items in the ComboBoxes + val smartModelItems = (0 until smartModel.itemCount).map { smartModel.getItemAt(it) } + .filter { modelItem -> + isVisible(ChatModel.values().entries.find { it.value.modelName == modelItem }?.value ?: return@filter false) + } + .sortedBy { modelItem -> + val model = + ChatModel.values().entries.find { it.value.modelName == modelItem }?.value ?: return@sortedBy "" + "${model.provider.name} - ${model.modelName}" + }.toList() + val fastModelItems = (0 until fastModel.itemCount).map { fastModel.getItemAt(it) } + .filter { modelItem -> + isVisible(ChatModel.values().entries.find { it.value.modelName == modelItem }?.value ?: return@filter false) + } + .sortedBy { modelItem -> + val model = + ChatModel.values().entries.find { it.value.modelName == modelItem }?.value ?: return@sortedBy "" + "${model.provider.name} - ${model.modelName}" + }.toList() + smartModel.removeAllItems() + fastModel.removeAllItems() + smartModelItems.forEach { smartModel.addItem(it) } + fastModelItems.forEach { fastModel.addItem(it) } + this.smartModel.isEditable = true + this.fastModel.isEditable = true + this.smartModel.renderer = getModelRenderer() + this.fastModel.renderer = getModelRenderer() + this.mainImageModel.isEditable = true + this.mainImageModel.renderer = getImageModelRenderer() + } + + + override fun dispose() { + } + + private fun getModelRenderer(): ListCellRenderer = object : SimpleListCellRenderer() { + override fun customize( + list: JList, + value: String?, + index: Int, + selected: Boolean, + hasFocus: Boolean + ) { + text = value // Here you can add more customization if needed + if (value != null) { + val model = ChatModel.values().entries.find { it.value.modelName == value }?.value + text = "${model?.provider?.name} - $value" + } + } + } + + private fun getImageModelRenderer(): ListCellRenderer = object : SimpleListCellRenderer() { + override fun customize( + list: JList, + value: String?, + index: Int, + selected: Boolean, + hasFocus: Boolean + ) { + text = value // Here you can add more customization if needed + } + } + + fun getExecutables(): Set { + val model = + ((executablesPanel.getComponent(0) as? JScrollPane)?.viewport?.view as? JList)?.model as? DefaultListModel + return model?.elements()?.toList()?.toSet() ?: emptySet() + } + + fun setExecutables(executables: Set) { + val model = + ((executablesPanel.getComponent(0) as? JScrollPane)?.viewport?.view as? JList)?.model as? DefaultListModel + model?.clear() + executables.forEach { model?.addElement(it) } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/config/AppSettingsConfigurable.kt b/src/main/kotlin/com/simiacryptus/aicoder/config/AppSettingsConfigurable.kt new file mode 100644 index 00000000..2e442ba7 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/config/AppSettingsConfigurable.kt @@ -0,0 +1,21 @@ +package com.simiacryptus.aicoder.config + +import com.simiacryptus.aicoder.util.UITools + +open class AppSettingsConfigurable : UIAdapter( + AppSettingsState.instance +) { + override fun read(component: AppSettingsComponent, settings: AppSettingsState) { + UITools.readKotlinUIViaReflection(settings = settings, component = component) + } + + override fun write(settings: AppSettingsState, component: AppSettingsComponent) { + UITools.writeKotlinUIViaReflection(settings, component, AppSettingsState::class) + } + + override fun getPreferredFocusedComponent() = component?.temperature + + override fun newComponent() = AppSettingsComponent() + + override fun newSettings() = AppSettingsState() +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/config/AppSettingsState.kt b/src/main/kotlin/com/simiacryptus/aicoder/config/AppSettingsState.kt new file mode 100644 index 00000000..a53350cc --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/config/AppSettingsState.kt @@ -0,0 +1,211 @@ +package com.simiacryptus.aicoder.config + +/** + * Stores and manages plugin configuration settings. + * + * This class is responsible for persisting and retrieving the plugin's + * configuration settings. It uses the IntelliJ Platform's persistence + * framework to save settings across IDE restarts. + */ +import com.fasterxml.jackson.annotation.JsonIgnore +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.util.io.FileUtil +import com.intellij.util.xmlb.XmlSerializerUtil +import com.simiacryptus.aicoder.util.PluginStartupActivity.Companion.addUserSuppliedModels +import com.simiacryptus.jopenai.models.APIProvider +import com.simiacryptus.jopenai.models.ImageModels +import com.simiacryptus.jopenai.models.OpenAIModels +import com.simiacryptus.skyenet.apps.plan.TaskSettingsBase +import com.simiacryptus.util.JsonUtil +import org.slf4j.LoggerFactory +import java.io.File + +@State(name = "org.intellij.sdk.settings.AppSettingsState", storages = [Storage("SdkSettingsPlugin.xml")]) +data class AppSettingsState( + var temperature: Double = 0.1, + var smartModel: String = OpenAIModels.GPT4o.modelName, + var fastModel: String = OpenAIModels.GPT4oMini.modelName, + var savedPlanConfigs: MutableMap = mutableMapOf(), + var mainImageModel: String = ImageModels.DallE3.modelName, + var listeningPort: Int = 8081, + var listeningEndpoint: String = "localhost", + var humanLanguage: String = "English", + var apiThreads: Int = 4, + var apiBase: Map? = mapOf("OpenAI" to "https://api.openai.com/v1"), + var apiKey: Map? = mapOf("OpenAI" to ""), + var modalTasks: Boolean = false, + var suppressErrors: Boolean = false, + var apiLog: Boolean = false, + var devActions: Boolean = false, + var editRequests: Boolean = false, + var disableAutoOpenUrls: Boolean = false, + var storeMetadata: String? = null, + var pluginHome: File = run { + var logPath = System.getProperty("idea.plugins.path") + if (logPath == null) { + logPath = System.getProperty("java.io.tmpdir") + } + if (logPath == null) { + logPath = System.getProperty("user.home") + } + File(logPath, "AICodingAsst") + }, + var showWelcomeScreen: Boolean = true, + var greetedVersion: String = "", + var shellCommand: String = getDefaultShell(), + var enableLegacyActions: Boolean = false, + var executables: MutableSet = mutableSetOf(), + var recentArguments: MutableList = mutableListOf(), + val recentCommands: MutableMap = mutableMapOf(), + var userSuppliedModels: MutableList = mutableListOf(), + var githubToken: String? = null, + var googleApiKey: String? = null, + var googleSearchEngineId: String? = null, + var awsProfile: String? = null, + var awsRegion: String? = null, + var awsBucket: String? = null +) : PersistentStateComponent { + data class SavedPlanConfig( + val name: String, + val temperature: Double, + val autoFix: Boolean, + val allowBlocking: Boolean, + val taskSettings: Map + ) + + private var onSettingsLoadedListeners = mutableListOf<() -> Unit>() + + @JsonIgnore + override fun getState(): SimpleEnvelope { + val value = JsonUtil.toJson(this) + return SimpleEnvelope(value) + } + + fun getRecentCommands(id: String) = recentCommands.computeIfAbsent(id) { MRUItems() } + + override fun loadState(state: SimpleEnvelope) { + state.value ?: return + val fromJson = try { + JsonUtil.fromJson(state.value!!, AppSettingsState::class.java) + } catch (e: Exception) { + log.warn("Error loading settings: ${state.value}", e) + AppSettingsState() + } + XmlSerializerUtil.copyBean(fromJson, this) + addUserSuppliedModels(fromJson.userSuppliedModels) + recentCommands.clear() + recentCommands.putAll(fromJson.recentCommands) + notifySettingsLoaded() + } + + fun addOnSettingsLoadedListener(listener: () -> Unit) { + onSettingsLoadedListeners.add(listener) + } + + private fun notifySettingsLoaded() { + onSettingsLoadedListeners.forEach { it() } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as AppSettingsState + if (temperature != other.temperature) return false + if (smartModel != other.smartModel) return false + if (fastModel != other.fastModel) return false + if (mainImageModel != other.mainImageModel) return false + if (listeningPort != other.listeningPort) return false + if (listeningEndpoint != other.listeningEndpoint) return false + if (humanLanguage != other.humanLanguage) return false + if (apiThreads != other.apiThreads) return false + if (apiBase != other.apiBase) return false + if (apiKey != other.apiKey) return false + if (modalTasks != other.modalTasks) return false + if (suppressErrors != other.suppressErrors) return false + if (apiLog != other.apiLog) return false + if (devActions != other.devActions) return false + if (editRequests != other.editRequests) return false + if (storeMetadata != other.storeMetadata) return false + if (FileUtil.filesEqual(pluginHome, other.pluginHome)) return false + if (recentCommands != other.recentCommands) return false + if (showWelcomeScreen != other.showWelcomeScreen) return false + if (greetedVersion != other.greetedVersion) return false + if (mainImageModel != other.mainImageModel) return false + if (enableLegacyActions != other.enableLegacyActions) return false + if (executables != other.executables) return false + //userSuppliedModels + if (userSuppliedModels.toTypedArray().contentDeepEquals(other.userSuppliedModels.toTypedArray()).not()) return false + if (googleApiKey != other.googleApiKey) return false + if (googleSearchEngineId != other.googleSearchEngineId) return false + if (githubToken != other.githubToken) return false + if (awsProfile != other.awsProfile) return false + if (awsRegion != other.awsRegion) return false + if (awsBucket != other.awsBucket) return false + return true + } + + override fun hashCode(): Int { + var result = temperature.hashCode() + result = 31 * result + smartModel.hashCode() + result = 31 * result + fastModel.hashCode() + result = 31 * result + enableLegacyActions.hashCode() + result = 31 * result + mainImageModel.hashCode() + result = 31 * result + listeningPort + result = 31 * result + listeningEndpoint.hashCode() + result = 31 * result + humanLanguage.hashCode() + result = 31 * result + apiThreads + result = 31 * result + (apiBase?.hashCode() ?: 0) + result = 31 * result + (apiKey?.hashCode() ?: 0) + result = 31 * result + modalTasks.hashCode() + result = 31 * result + suppressErrors.hashCode() + result = 31 * result + apiLog.hashCode() + result = 31 * result + devActions.hashCode() + result = 31 * result + editRequests.hashCode() + result = 31 * result + (storeMetadata?.hashCode() ?: 0) + result = 31 * result + FileUtil.fileHashCode(pluginHome) + result = 31 * result + recentCommands.hashCode() + result = 31 * result + showWelcomeScreen.hashCode() + result = 31 * result + greetedVersion.hashCode() + result = 31 * result + mainImageModel.hashCode() + result = 31 * result + enableLegacyActions.hashCode() + result = 31 * result + executables.hashCode() + result = 31 * result + userSuppliedModels.hashCode() + result = 31 * result + (googleApiKey?.hashCode() ?: 0) + result = 31 * result + (googleSearchEngineId?.hashCode() ?: 0) + result = 31 * result + (githubToken?.hashCode() ?: 0) + result = 31 * result + (awsProfile?.hashCode() ?: 0) + result = 31 * result + (awsRegion?.hashCode() ?: 0) + result = 31 * result + (awsBucket?.hashCode() ?: 0) + return result + } + + companion object { + val log = LoggerFactory.getLogger(AppSettingsState::class.java) + var auxiliaryLog: File? = null + const val WELCOME_VERSION: String = "1.5.0" + + @JvmStatic + val instance: AppSettingsState by lazy { + ApplicationManager.getApplication()?.getService(AppSettingsState::class.java) ?: AppSettingsState() + } + + fun String.imageModel(): ImageModels { + return ImageModels.values().firstOrNull { + it.modelName == this || it.name == this + } ?: ImageModels.DallE3 + } + + fun getDefaultShell() = if (System.getProperty("os.name").lowercase().contains("win")) "powershell" else "bash" + } + + data class UserSuppliedModel( + var displayName: String = "", + var modelId: String = "", + var provider: APIProvider = APIProvider.OpenAI + ) + + var analyticsEnabled: Boolean = false +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/config/MRUItems.kt b/src/main/kotlin/com/simiacryptus/aicoder/config/MRUItems.kt new file mode 100644 index 00000000..dab97063 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/config/MRUItems.kt @@ -0,0 +1,110 @@ +package com.simiacryptus.aicoder.config + +import com.fasterxml.jackson.annotation.JsonIgnore +import java.io.Serializable +import java.time.Instant +import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.locks.ReentrantReadWriteLock +import kotlin.concurrent.read +import kotlin.concurrent.write +import kotlin.math.min + +class MRUItems : Serializable { + + companion object { + const val DEFAULT_LIMIT = 10 + } + + data class HistoryItem(val instruction: String, var usageCount: Int, var lastUsed: Instant) : Serializable + + val history: MutableList = CopyOnWriteArrayList() + + private val lock = ReentrantReadWriteLock() + + var historyLimit = DEFAULT_LIMIT + set(value) { + require(value > 0) { "History limit must be positive" } + lock.write { + field = value + trimHistories() + } + } + + override fun equals(other: Any?): Boolean { + return other is MRUItems && history == other.history + } + + override fun hashCode(): Int { + return history.hashCode() + } + + fun addInstructionToHistory(instruction: CharSequence) { + lock.write { + val instructionStr = instruction.toString() + val existingItem = history.find { it.instruction == instructionStr } + if (existingItem != null) { + existingItem.usageCount++ + existingItem.lastUsed = Instant.now() + history.remove(existingItem) + history.add(0, existingItem) + } else { + history.add(0, HistoryItem(instructionStr, 1, Instant.now())) + } + trimHistories() + } + } + + @JsonIgnore + fun getMostUsed(limit: Int = DEFAULT_LIMIT): List { + return lock.read { + history + .sortedByDescending { it.usageCount } + .take(min(limit, historyLimit)) + .map { it.instruction } + } + } + + @JsonIgnore + fun getMostRecent(limit: Int = DEFAULT_LIMIT): List { + return lock.read { + history.take(min(limit, historyLimit)).map { it.instruction } + } + } + + fun clear() { + lock.write { + history.clear() + } + } + + fun size(): Int = lock.read { history.size } + + fun isEmpty(): Boolean = lock.read { history.isEmpty() } + + fun remove(item: String) { + lock.write { + history.removeIf { it.instruction == item } + } + } + + private fun trimHistories() { + lock.write { + if (history.size > historyLimit) { + history.subList(historyLimit, history.size).clear() + } + } + } + + fun contains(item: String): Boolean { + return lock.read { + history.any { it.instruction == item } + } + } + + override fun toString(): String { + return lock.read { + "MRUItems(mostUsed=${getMostUsed(5)}, mostRecent=${getMostRecent(5)}, size=${history.size})" + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/Name.kt b/src/main/kotlin/com/simiacryptus/aicoder/config/Name.kt similarity index 62% rename from src/main/kotlin/com/github/simiacryptus/aicoder/config/Name.kt rename to src/main/kotlin/com/simiacryptus/aicoder/config/Name.kt index d113009a..9371dd59 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/Name.kt +++ b/src/main/kotlin/com/simiacryptus/aicoder/config/Name.kt @@ -1,6 +1,6 @@ -package com.github.simiacryptus.aicoder.config +package com.simiacryptus.aicoder.config @Retention(AnnotationRetention.RUNTIME) annotation class Name(val value: String) - + diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/config/SimpleEnvelope.kt b/src/main/kotlin/com/simiacryptus/aicoder/config/SimpleEnvelope.kt similarity index 50% rename from src/main/kotlin/com/github/simiacryptus/aicoder/config/SimpleEnvelope.kt rename to src/main/kotlin/com/simiacryptus/aicoder/config/SimpleEnvelope.kt index 4dfdd5ca..ecd5a39f 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/config/SimpleEnvelope.kt +++ b/src/main/kotlin/com/simiacryptus/aicoder/config/SimpleEnvelope.kt @@ -1,3 +1,3 @@ -package com.github.simiacryptus.aicoder.config +package com.simiacryptus.aicoder.config class SimpleEnvelope(var value: String? = null) \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt b/src/main/kotlin/com/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt new file mode 100644 index 00000000..ec182210 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/config/StaticAppSettingsConfigurable.kt @@ -0,0 +1,295 @@ +package com.simiacryptus.aicoder.config + +import com.simiacryptus.aicoder.util.IdeaChatClient +import com.simiacryptus.aicoder.util.PluginStartupActivity.Companion.addUserSuppliedModels +import com.simiacryptus.jopenai.models.APIProvider +import java.awt.* +import java.io.File +import java.io.FileOutputStream +import javax.swing.* +import javax.swing.table.DefaultTableModel + +class StaticAppSettingsConfigurable : AppSettingsConfigurable() { + override fun apply() { + super.apply() + addUserSuppliedModels(settingsInstance.userSuppliedModels) + if (settingsInstance.apiLog) { + val file = File(AppSettingsState.instance.pluginHome, "openai.log") + if (AppSettingsState.auxiliaryLog?.absolutePath?.lowercase() != file.absolutePath.lowercase()) { + file.deleteOnExit() + AppSettingsState.auxiliaryLog = file + IdeaChatClient.instance.logStreams.add(FileOutputStream(file, true).buffered()) + } + } else { + AppSettingsState.auxiliaryLog = null + IdeaChatClient.instance.logStreams.retainAll { it.close(); false } + } + } + + override fun build(component: AppSettingsComponent): JComponent { + val tabbedPane = com.intellij.ui.components.JBTabbedPane() + try {// Basic Settings Tab + val basicSettingsPanel = JPanel(BorderLayout()).apply { + add(JPanel(BorderLayout()).apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Smart Model:")) + add(component.smartModel) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Fast Model:")) + add(component.fastModel) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Image Model:")) + add(component.mainImageModel) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Temperature:")) + add(component.temperature) + }) + add(JPanel(BorderLayout()).apply { + add(JLabel("API Configurations:"), BorderLayout.NORTH) + add(component.apis, BorderLayout.CENTER) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Executables:")) + add(component.executablesPanel) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Human Language:")) + add(component.humanLanguage) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("GitHub Token:")) + add(component.githubToken) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Google API Key:")) + add(component.googleApiKey) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Google Search Engine ID:")) + add(component.googleSearchEngineId) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("AWS Profile:")) + add(component.awsProfile) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("AWS Region:")) + add(component.awsRegion) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("AWS Bucket:")) + add(component.awsBucket) + }) + }) + } + tabbedPane.addTab("Basic Settings", basicSettingsPanel) + } catch (e: Exception) { + log.warn("Error building Basic Settings", e) + } + + tabbedPane.addTab("Developer Tools", JPanel(BorderLayout()).apply { + try { + add(JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Developer Tools:")) + add(component.devActions) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Enable Legacy Actions:")) + add(component.enableLegacyActions) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + // Removed sections that reference non-existing components + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Ignore Errors:")) + add(component.suppressErrors) + }) + }, BorderLayout.NORTH) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Edit API Requests:")) + add(component.editRequests) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Disable Auto-Open URLs:")) + add(component.disableAutoOpenUrls) + }) + add(JPanel(BorderLayout()).apply { + add(JLabel("Store Metadata (JSON):"), BorderLayout.NORTH) + val scrollPane = JScrollPane(component.storeMetadata) + scrollPane.preferredSize = Dimension(300, 100) + add(scrollPane, BorderLayout.CENTER) + }) + add(JPanel(BorderLayout()).apply { + add(JLabel("User-Supplied Models:"), BorderLayout.NORTH) + add(JScrollPane(component.userSuppliedModels).apply { + preferredSize = Dimension(500, 200) + }, BorderLayout.CENTER) + add(JPanel(GridBagLayout()).apply { + val gbc = GridBagConstraints().apply { + gridx = 0 + gridy = 0 + fill = GridBagConstraints.HORIZONTAL + weightx = 1.0 + } + add(component.addUserModelButton, gbc) + gbc.gridx++ + add(component.removeUserModelButton, gbc) + }, BorderLayout.SOUTH) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Enable API Log:")) + add(component.apiLog) + add(component.openApiLog) + add(component.clearApiLog) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Server Port:")) + add(component.listeningPort) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Server Endpoint:")) + add(component.listeningEndpoint) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Plugin Home:")) + add(component.pluginHome) + add(component.choosePluginHome) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + add(JLabel("Shell Command:")) + add(component.shellCommand) + }) + add(JPanel(FlowLayout(FlowLayout.LEFT)).apply { + //add(JLabel("Show Welcome Screen:")) + add(component.showWelcomeScreen) + }) + }, BorderLayout.NORTH) + } catch (e: Exception) { + log.warn("Error building Developer Tools", e) + } + }) + + tabbedPane.addTab("Usage", JPanel(BorderLayout()).apply { + try { + add(component.usage, BorderLayout.CENTER) + } catch (e: Exception) { + log.warn("Error building Usage", e) + } + }) + + return tabbedPane + } + + override fun write(settings: AppSettingsState, component: AppSettingsComponent) { + try { + component.githubToken.text = settings.githubToken ?: "" + component.googleApiKey.text = settings.googleApiKey ?: "" + component.googleSearchEngineId.text = settings.googleSearchEngineId ?: "" + component.awsProfile.text = settings.awsProfile ?: "" + component.awsRegion.text = settings.awsRegion ?: "" + component.awsBucket.text = settings.awsBucket ?: "" + component.humanLanguage.text = settings.humanLanguage + component.listeningPort.text = settings.listeningPort.toString() + component.listeningEndpoint.text = settings.listeningEndpoint + component.suppressErrors.isSelected = settings.suppressErrors + component.disableAutoOpenUrls.isSelected = settings.disableAutoOpenUrls + component.fastModel.selectedItem = settings.fastModel + component.smartModel.selectedItem = settings.smartModel + component.apiLog.isSelected = settings.apiLog + component.devActions.isSelected = settings.devActions + component.editRequests.isSelected = settings.editRequests + component.mainImageModel.selectedItem = settings.mainImageModel + component.storeMetadata.text = settings.storeMetadata ?: "" + component.temperature.text = settings.temperature.toString() + component.pluginHome.text = settings.pluginHome.absolutePath + component.shellCommand.text = settings.shellCommand + val model = component.apis.model as DefaultTableModel + model.rowCount = 0 // Clear existing rows + APIProvider.values().forEach { value -> + val key = value.name + model.addRow(arrayOf(key, settings.apiKey?.get(key) ?: "", settings.apiBase?.get(key) ?: value.base)) + } + component.showWelcomeScreen.isSelected = settings.showWelcomeScreen + component.enableLegacyActions.isSelected = settings.enableLegacyActions + component.setExecutables(settings.executables) + component.setUserSuppliedModels(settings.userSuppliedModels) + } catch (e: Exception) { + log.warn("Error setting UI", e) + } + } + + override fun read(component: AppSettingsComponent, settings: AppSettingsState) { + try { + settings.githubToken = component.githubToken.text.takeIf { it.isNotBlank() } + settings.googleApiKey = component.googleApiKey.text.takeIf { it.isNotBlank() } + settings.googleSearchEngineId = component.googleSearchEngineId.text.takeIf { it.isNotBlank() } + settings.awsProfile = component.awsProfile.text.takeIf { it.isNotBlank() } + settings.awsRegion = component.awsRegion.text.takeIf { it.isNotBlank() } + settings.awsBucket = component.awsBucket.text.takeIf { it.isNotBlank() } + settings.executables = component.getExecutables().toMutableSet() + settings.humanLanguage = component.humanLanguage.text + settings.listeningPort = component.listeningPort.text.safeInt() + settings.listeningEndpoint = component.listeningEndpoint.text + settings.suppressErrors = component.suppressErrors.isSelected + settings.fastModel = component.fastModel.selectedItem as String + settings.smartModel = component.smartModel.selectedItem as String + settings.apiLog = component.apiLog.isSelected + settings.devActions = component.devActions.isSelected + settings.editRequests = component.editRequests.isSelected + settings.disableAutoOpenUrls = component.disableAutoOpenUrls.isSelected + settings.temperature = component.temperature.text.safeDouble() + settings.storeMetadata = component.storeMetadata.text.takeIf { it.isNotBlank() } + settings.mainImageModel = (component.mainImageModel.selectedItem as String) + settings.pluginHome = File(component.pluginHome.text) + settings.shellCommand = component.shellCommand.text + settings.enableLegacyActions = component.enableLegacyActions.isSelected + + val tableModel = component.apis.model as DefaultTableModel + for (row in 0 until tableModel.rowCount) { + val provider = tableModel.getValueAt(row, 0) as String + val key = tableModel.getValueAt(row, 1) as String + val base = tableModel.getValueAt(row, 2) as String + if (key.isNotBlank()) { + settings.apiKey = settings.apiKey?.toMutableMap()?.apply { put(provider, key) } + settings.apiBase = settings.apiBase?.toMutableMap()?.apply { put(provider, base) } + } else { + settings.apiKey = settings.apiKey?.toMutableMap()?.apply { remove(provider) } + settings.apiBase = settings.apiBase?.toMutableMap()?.apply { remove(provider) } + } + } + settings.showWelcomeScreen = component.showWelcomeScreen.isSelected + settings.userSuppliedModels = component.getUserSuppliedModels().toMutableList() + } catch (e: Exception) { + log.warn("Error reading UI", e) + } + } + + companion object { + val log = com.intellij.openapi.diagnostic.Logger.getInstance(StaticAppSettingsConfigurable::class.java) + } +} + +fun String?.safeInt() = if (null == this) 0 else when { + isEmpty() -> 0 + else -> try { + toInt() + } catch (e: NumberFormatException) { + 0 + } +} + +fun String?.safeDouble() = if (null == this) 0.0 else when { + isEmpty() -> 0.0 + else -> try { + toDouble() + } catch (e: NumberFormatException) { + 0.0 + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/config/UIAdapter.kt b/src/main/kotlin/com/simiacryptus/aicoder/config/UIAdapter.kt new file mode 100644 index 00000000..90f83a03 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/config/UIAdapter.kt @@ -0,0 +1,91 @@ +package com.simiacryptus.aicoder.config + +import com.intellij.openapi.Disposable +import com.intellij.openapi.options.Configurable +import com.simiacryptus.aicoder.util.UITools +import org.slf4j.LoggerFactory +import javax.swing.JComponent + +abstract class UIAdapter( + protected val settingsInstance: S, + protected var component: C? = null, +) : Configurable { + + companion object { + private val log = LoggerFactory.getLogger(UIAdapter::class.java) + } + + @Volatile + private var mainPanel: JComponent? = null + override fun getDisplayName(): String { + return "AICoder Settings" + } + + override fun getPreferredFocusedComponent(): JComponent? = null + + override fun createComponent(): JComponent? { + if (null == mainPanel) { + synchronized(this) { + if (null == mainPanel) { + try { + val component = newComponent() + this.component = component + mainPanel = build(component) + write(settingsInstance, component) + } catch (e: Exception) { + log.error("Error creating component", e) + } + } + } + } + return mainPanel + } + + abstract fun newComponent(): C + abstract fun newSettings(): S + private fun getSettings(component: C? = this.component) = try { + when (component) { + null -> settingsInstance + else -> { + val buffer = newSettings() + read(component, buffer) + buffer + } + } + } catch (e: Exception) { + log.error("Error reading settings", e) + settingsInstance + } + + override fun isModified() = when { + component == null -> false + getSettings() != settingsInstance -> true + else -> false + } + + override fun apply() { + if (component != null) read(component!!, settingsInstance) + } + + override fun reset() { + if (component != null) write(settingsInstance, component!!) + } + + override fun disposeUIResources() { + val component = component + this.component = null + if (component != null && component is Disposable) component.dispose() + } + + open fun build(component: C): JComponent = + UITools.buildFormViaReflection(component, false)!! + + open fun read(component: C, settings: S) { + UITools.readKotlinUIViaReflection(settings, component, Any::class) + } + + open fun write(settings: S, component: C) { + UITools.writeKotlinUIViaReflection(settings, component, Any::class) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/config/UsageTable.kt b/src/main/kotlin/com/simiacryptus/aicoder/config/UsageTable.kt new file mode 100644 index 00000000..5cc6b473 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/config/UsageTable.kt @@ -0,0 +1,164 @@ +package com.simiacryptus.aicoder.config + +import com.intellij.ui.components.JBScrollPane +import com.intellij.ui.table.JBTable +import com.simiacryptus.aicoder.util.IdeaChatClient +import com.simiacryptus.skyenet.core.platform.model.UsageInterface +import org.jdesktop.swingx.JXTable +import java.awt.BorderLayout +import java.awt.Component +import java.awt.event.ActionEvent +import java.util.* +import javax.swing.AbstractAction +import javax.swing.JButton +import javax.swing.JPanel +import javax.swing.JTable +import javax.swing.table.AbstractTableModel +import javax.swing.table.DefaultTableCellRenderer + +class UsageTable( + val usage: UsageInterface +) : JPanel(BorderLayout()) { + + private val buttonPanel = JPanel() + val columnNames = arrayOf("Model", "Prompt", "Completion", "Cost") + + val rowData by lazy { + val usageData = usage.getUserUsageSummary(IdeaChatClient.localUser).map { entry -> + listOf( + entry.key.modelName, + entry.value.prompt_tokens.toString(), + entry.value.completion_tokens.toString(), + String.format("%.2f", entry.value.cost) + ).toMutableList() + } + // Calculate totals + val totalPromptTokens = usageData.sumOf { it[1].toString().toInt() } + val totalCompletionTokens = usageData.sumOf { it[2].toString().toInt() } + val totalCost = usageData.sumOf { it[3].toString().toDouble() } + // Add totals row + (usageData + listOf( + listOf( + "TOTAL", + totalPromptTokens.toString(), + totalCompletionTokens.toString(), + String.format("%.2f", totalCost) + ).toMutableList() + )).toMutableList() + } + + private val dataModel by lazy { + object : AbstractTableModel() { + override fun getColumnName(column: Int): String { + return columnNames.get(column).toString() + } + + override fun getValueAt(row: Int, col: Int): Any { + return rowData[row][col] + } + + override fun isCellEditable(row: Int, column: Int): Boolean { + // Make the total row non-editable + return row != rowData.size - 1 + } + + override fun getRowCount(): Int { + return rowData.size + } + + override fun getColumnCount(): Int { + return columnNames.size + } + + + override fun setValueAt(value: Any, row: Int, col: Int) { + // Prevent editing total row + if (row == rowData.size - 1) return + val strings = rowData[row] + strings[col] = value.toString() + fireTableCellUpdated(row, col) + } + + } + } + + private val jtable by lazy { JBTable(dataModel) } + + private val scrollpane by lazy { JBScrollPane(jtable) } + + + private val clearButton by lazy { + JButton(object : AbstractAction("Clear") { + override fun actionPerformed(e: ActionEvent?) { + rowData.clear() + usage.clear() + this@UsageTable.parent.invalidate() + } + }) + } + + init { + // Custom renderer for the total row + val totalRowRenderer = object : DefaultTableCellRenderer() { + override fun getTableCellRendererComponent( + table: JTable?, + value: Any?, + isSelected: Boolean, + hasFocus: Boolean, + row: Int, + column: Int + ): Component { + val c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column) + if (row == table?.model?.rowCount?.minus(1)) { + font = font.deriveFont(font.style or java.awt.Font.BOLD) + } + return c + } + } + + jtable.columnModel.getColumn(0).cellRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(1).cellRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(2).cellRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(3).cellRenderer = DefaultTableCellRenderer() + // Apply the total row renderer to all columns + for (i in 0..3) { + val column = jtable.columnModel.getColumn(i) + column.cellRenderer = totalRowRenderer + } + + + val editor = object : JXTable.GenericEditor() { + override fun isCellEditable(anEvent: EventObject?) = false + } + jtable.columnModel.getColumn(0).cellEditor = editor + jtable.columnModel.getColumn(1).cellEditor = editor + jtable.columnModel.getColumn(2).cellEditor = editor + jtable.columnModel.getColumn(3).cellEditor = editor + + jtable.columnModel.getColumn(0).headerRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(1).headerRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(2).headerRenderer = DefaultTableCellRenderer() + jtable.columnModel.getColumn(3).headerRenderer = DefaultTableCellRenderer() + + // Set the preferred width for the first column (checkboxes) to the header label width + initCol(0) + initCol(1) + initCol(2) + initCol(3) + + jtable.tableHeader.defaultRenderer = DefaultTableCellRenderer() + + add(scrollpane, BorderLayout.CENTER) + buttonPanel.add(clearButton) + add(buttonPanel, BorderLayout.SOUTH) + } + + private fun initCol(idx: Int) { + val headerRenderer = jtable.tableHeader.defaultRenderer + val headerValue = jtable.columnModel.getColumn(idx).headerValue + val headerComp = headerRenderer.getTableCellRendererComponent(jtable, headerValue, false, false, 0, idx) + jtable.columnModel.getColumn(idx).preferredWidth = headerComp.preferredSize.width + } + + companion object +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/simiacryptus/aicoder/ui/SettingsWidgetFactory.kt b/src/main/kotlin/com/simiacryptus/aicoder/ui/SettingsWidgetFactory.kt similarity index 68% rename from src/main/kotlin/com/github/simiacryptus/aicoder/ui/SettingsWidgetFactory.kt rename to src/main/kotlin/com/simiacryptus/aicoder/ui/SettingsWidgetFactory.kt index d2cd421d..a02a7b32 100644 --- a/src/main/kotlin/com/github/simiacryptus/aicoder/ui/SettingsWidgetFactory.kt +++ b/src/main/kotlin/com/simiacryptus/aicoder/ui/SettingsWidgetFactory.kt @@ -1,9 +1,6 @@ -package com.github.simiacryptus.aicoder.ui +package com.simiacryptus.aicoder.ui -import com.github.simiacryptus.aicoder.AppServer -import com.github.simiacryptus.aicoder.actions.generic.SessionProxyServer -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.util.BrowseUtil.browse +import aicoder.actions.SessionProxyServer import com.intellij.openapi.project.Project import com.intellij.openapi.ui.popup.JBPopup import com.intellij.openapi.ui.popup.JBPopupFactory @@ -12,18 +9,26 @@ import com.intellij.openapi.ui.popup.LightweightWindowEvent import com.intellij.openapi.wm.StatusBar import com.intellij.openapi.wm.StatusBarWidget import com.intellij.openapi.wm.StatusBarWidgetFactory -import com.intellij.ui.SimpleListCellRenderer import com.intellij.ui.components.JBList import com.intellij.ui.treeStructure.Tree +import com.simiacryptus.aicoder.AppServer +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.config.UsageTable +import com.simiacryptus.aicoder.util.BrowseUtil.browse import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.ApplicationServicesConfig.dataStorageRoot import icons.MyIcons import kotlinx.coroutines.CoroutineScope import java.awt.* import java.awt.datatransfer.StringSelection +import java.awt.event.KeyEvent import java.awt.event.MouseAdapter import java.awt.event.MouseEvent import java.net.URI +import java.util.* +import javax.accessibility.AccessibleContext import javax.swing.* import javax.swing.tree.DefaultMutableTreeNode import javax.swing.tree.DefaultTreeModel @@ -44,12 +49,12 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { val root = DefaultMutableTreeNode(title) // Filter models by providers that have API keys set val providers = models() - .filter { model -> + .filter { model -> val providerName = model.second.provider.name AppSettingsState.instance.apiKey?.get(providerName)?.isNotEmpty() == true } .groupBy { it.second.provider } - + for ((provider, models) in providers) { val providerNode = DefaultMutableTreeNode(provider.name) for (model in models) { @@ -63,6 +68,22 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { } val treeModel = DefaultTreeModel(root) val tree = Tree(treeModel) + // Add accessibility description + tree.accessibleContext.accessibleDescription = getMessage("tree.description", title) + // Add keyboard navigation + tree.inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "toggle") + tree.inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "select") + // Add screen reader support for selection changes + tree.addTreeSelectionListener { + val selectedNode = tree.lastSelectedPathComponent?.toString() + if (selectedNode != null) { + tree.accessibleContext.firePropertyChange( + AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY, + null, + getMessage("tree.selected", selectedNode) + ) + } + } tree.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION tree.isRootVisible = false tree.showsRootHandles = true @@ -88,10 +109,25 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { private val temperatureSlider by lazy { val slider = JSlider(0, 100, (AppSettingsState.instance.temperature * 100).toInt()) + // Add accessibility description + slider.accessibleContext.accessibleDescription = getMessage("slider.description") + // Add keyboard increments + slider.majorTickSpacing = 10 + slider.minorTickSpacing = 1 + slider.snapToTicks = true + // Add screen reader announcements for value changes + slider.addChangeListener { + slider.accessibleContext.firePropertyChange( + AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, + null, + getMessage("slider.value", slider.value / 100.0) + ) + } slider.addChangeListener { AppSettingsState.instance.temperature = slider.value / 100.0 } val panel = JPanel(BorderLayout(5, 5)) // Add padding panel.add(slider, BorderLayout.CENTER) val label = JLabel(String.format("%.2f", AppSettingsState.instance.temperature)) + label.accessibleContext.accessibleDescription = getMessage("label.temperature") slider.addChangeListener { label.text = String.format("%.2f", slider.value / 100.0) } panel.add(label, BorderLayout.EAST) panel @@ -99,6 +135,12 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { private fun createServerControlPanel(): JPanel { val panel = JPanel(BorderLayout()) + panel.accessibleContext.accessibleDescription = getMessage("panel.server.description") + sessionsList.accessibleContext.accessibleDescription = getMessage("list.sessions.description") + sessionsList.accessibleContext.accessibleName = getMessage("list.sessions.name") + // Add keyboard navigation for sessions list + sessionsList.inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "activate") + sessionsList.inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "activate") // Server control buttons val buttonPanel = JPanel(FlowLayout(FlowLayout.LEFT)) val startButton = JButton("Start Server") @@ -145,7 +187,7 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { copyButton.addActionListener { val session = sessionsList.selectedValue if (session != null) { - val link = getSessionLink(session) + val link = Companion.getSessionLink(session) val selection = StringSelection(link) Toolkit.getDefaultToolkit().systemClipboard.setContents(selection, null) } @@ -153,7 +195,7 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { openButton.addActionListener { val session = sessionsList.selectedValue if (session != null) { - browse(URI(getSessionLink(session))) + browse(URI(Companion.getSessionLink(session))) } } actionPanel.add(copyButton) @@ -165,16 +207,12 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { fun updateSessionsList() { sessionsListModel.clear() - SessionProxyServer.chats.keys.forEach { sessionsListModel.addElement(it) } - SessionProxyServer.agents.keys.forEach { sessionsListModel.addElement(it) } - } - - private fun getSessionLink(session: Session): String { - val settings = AppSettingsState.instance - return "http://${settings.listeningEndpoint}:${settings.listeningPort}/?session=${session.sessionId}" + (SessionProxyServer.chats.keys + SessionProxyServer.agents.keys).distinct().forEach { + sessionsListModel.addElement(it) + } } - private class SessionListRenderer : ListCellRenderer { + private inner class SessionListRenderer : ListCellRenderer { private val label = JLabel() override fun getListCellRendererComponent( list: JList?, @@ -183,7 +221,20 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { isSelected: Boolean, cellHasFocus: Boolean ): Component { - label.text = "Session ${value?.sessionId?.take(8)}" + label.text = if (value != null) { + try { + val sessionName = ApplicationServices.metadataStorageFactory(dataStorageRoot).getSessionName(null, value) + when { + sessionName.isNullOrBlank() -> getDefaultSessionLabel(value) + else -> "$sessionName (${value.sessionId.take(8)})" + } + } catch (e: Exception) { + getDefaultSessionLabel(value) + } + } else { + "Unknown Session" + } + if (isSelected) { label.background = list?.selectionBackground label.foreground = list?.selectionForeground @@ -191,28 +242,32 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { label.background = list?.background label.foreground = list?.foreground } + // Add accessibility name to each list item + label.accessibleContext.accessibleName = label.text + label.accessibleContext.accessibleDescription = getMessage("session.item.description", label.text) return label } - } - - // Removed createModelList() as we are using tree views instead + private fun getDefaultSessionLabel(session: Session): String { + return "Session ${session.sessionId.take(8)}" + } + } init { AppSettingsState.instance.addOnSettingsLoadedListener { statusBar?.updateWidget(ID()) } - // Initialize selection for both trees on EDT - if (AppSettingsState.instance.smartModel.isNotEmpty()) { - SwingUtilities.invokeLater { - setSelectedModel(smartModelTree, AppSettingsState.instance.smartModel) - } + // Initialize selection for both trees on EDT + if (AppSettingsState.instance.smartModel.isNotEmpty()) { + SwingUtilities.invokeLater { + setSelectedModel(smartModelTree, AppSettingsState.instance.smartModel) } - if (AppSettingsState.instance.fastModel.isNotEmpty()) { - SwingUtilities.invokeLater { - setSelectedModel(fastModelTree, AppSettingsState.instance.fastModel) - } + } + if (AppSettingsState.instance.fastModel.isNotEmpty()) { + SwingUtilities.invokeLater { + setSelectedModel(fastModelTree, AppSettingsState.instance.fastModel) } + } } fun models() = ChatModel.values().filter { it.value != null && isVisible(it.value!!) }.toList() @@ -252,22 +307,6 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { return header } - private fun getRenderer(): ListCellRenderer = object : SimpleListCellRenderer() { - override fun customize( - list: JList, - value: String?, - index: Int, - selected: Boolean, - hasFocus: Boolean - ) { - text = value // Here you can add more customization if needed - if (value != null) { - val model = models().find { it.second.modelName == value } - text = "${model?.second?.provider?.name} - $value" // Enhance label formatting - } - } - } - private fun setSelectedModel(tree: JTree, modelName: String) { val root = tree.model as DefaultTreeModel val rootNode = root.root as DefaultMutableTreeNode @@ -287,11 +326,16 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { override fun getPopup(): JBPopup { + // Update sessions list before creating popup + updateSessionsList() val panel = JPanel(BorderLayout()) + panel.accessibleContext.accessibleDescription = getMessage("popup.description") panel.add(createHeader(), BorderLayout.NORTH) // Create tabbed pane val tabbedPane = JTabbedPane() + // Add accessibility descriptions for tabs + tabbedPane.accessibleContext.accessibleDescription = getMessage("tabs.description") // Smart model tab val smartModelPanel = JPanel(BorderLayout()) smartModelPanel.add(JScrollPane(smartModelTree), BorderLayout.CENTER) @@ -302,6 +346,10 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { tabbedPane.addTab("Fast Model", fastModelPanel) // Add server control tab tabbedPane.addTab("Server", createServerControlPanel()) + // Add usage tab + val usagePanel = JPanel(BorderLayout()) + usagePanel.add(UsageTable(ApplicationServices.usageManager), BorderLayout.CENTER) + tabbedPane.addTab("Usage", usagePanel) panel.add(tabbedPane, BorderLayout.CENTER) panel.add(temperatureSlider, BorderLayout.SOUTH) @@ -315,16 +363,10 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { updateSessionsList() } }) - - // Removed smartModelList selection listener as tree handles it - - // Removed fastModelList selection listener as tree handles it return popup } - // Optionally, update getSelectedValue to reflect selected models from trees override fun getSelectedValue(): String { -// return "Smart: ${AppSettingsState.instance.smartModel} | Fast: ${AppSettingsState.instance.fastModel}" return AppSettingsState.instance.smartModel } @@ -334,18 +376,27 @@ class SettingsWidgetFactory : StatusBarWidgetFactory { } else { "Server stopped" } - return "Smart Model: ${AppSettingsState.instance.smartModel}\n" + - "Fast Model: ${AppSettingsState.instance.fastModel}\n" + - "Temperature: ${AppSettingsState.instance.temperature}\n" + - serverStatus + return """ + Smart Model: ${AppSettingsState.instance.smartModel}
+ Fast Model: ${AppSettingsState.instance.fastModel}
+ Temperature: ${AppSettingsState.instance.temperature}
+ $serverStatus + """.trimIndent().trim() } - // Companion object removed, making isVisible a regular function private fun isVisible(it: ChatModel): Boolean { - // Temporarily allow all models to be visible for debugging return true } + companion object { + private val messages = ResourceBundle.getBundle("messages.SettingsWidget") + private fun getMessage(key: String, vararg args: Any): String = + String.format(messages.getString(key), *args) + + fun getSessionLink(session: Session) = + "http://${AppSettingsState.instance.listeningEndpoint}:${AppSettingsState.instance.listeningPort}/#${session.sessionId}" + } + } override fun getId(): String { diff --git a/src/main/kotlin/com/simiacryptus/aicoder/ui/TokenCountWidgetFactory.kt b/src/main/kotlin/com/simiacryptus/aicoder/ui/TokenCountWidgetFactory.kt new file mode 100644 index 00000000..4e60a20f --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/ui/TokenCountWidgetFactory.kt @@ -0,0 +1,364 @@ +package com.simiacryptus.aicoder.ui + +import com.intellij.ide.projectView.impl.AbstractProjectViewPane +import com.intellij.ide.projectView.impl.ProjectViewListener +import com.intellij.openapi.editor.event.DocumentEvent +import com.intellij.openapi.editor.event.DocumentListener +import com.intellij.openapi.editor.event.SelectionEvent +import com.intellij.openapi.editor.event.SelectionListener +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.FileEditorManagerEvent +import com.intellij.openapi.fileEditor.FileEditorManagerListener +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ProjectManager +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.isFile +import com.intellij.openapi.vfs.readText +import com.intellij.openapi.wm.StatusBar +import com.intellij.openapi.wm.StatusBarWidget +import com.intellij.openapi.wm.StatusBarWidgetFactory +import com.simiacryptus.jopenai.util.GPT4Tokenizer +import com.simiacryptus.skyenet.core.util.FileValidationUtils.Companion.isGitignore +import com.simiacryptus.skyenet.core.util.FileValidationUtils.Companion.isLLMIncludableFile +import kotlinx.coroutines.CoroutineScope +import java.awt.event.MouseEvent +import java.io.File +import java.util.* +import java.util.concurrent.LinkedBlockingDeque +import java.util.concurrent.ThreadPoolExecutor +import java.util.concurrent.TimeUnit +import javax.swing.event.TreeSelectionEvent +import javax.swing.event.TreeSelectionListener + +class TokenCountWidgetFactory : StatusBarWidgetFactory { + companion object { + private val messages = ResourceBundle.getBundle("messages.TokenCountWidget") + private fun getMessage(key: String, vararg args: Any): String = + String.format(messages.getString(key), *args) + + val workQueue = LinkedBlockingDeque() + val pool = ThreadPoolExecutor( + /* corePoolSize = */ 1, /* maximumPoolSize = */ 1, + /* keepAliveTime = */ 60L, /* unit = */ TimeUnit.SECONDS, + /* workQueue = */ workQueue + ) + } + + class TokenCountWidget : StatusBarWidget, StatusBarWidget.TextPresentation { + + private var tokenCount: Int = 0 + val codex = GPT4Tokenizer(false) + private var tooltipDetails: String = "Current file token count" + private var isCalculating: Boolean = false + private var animationCounter: Int = 0 + + override fun ID(): String { + return "StatusBarComponent" + } + + override fun getPresentation(): StatusBarWidget.WidgetPresentation { + return this + } + + fun resolve(path: Array, candidates: List): VirtualFile? { + if (candidates.isEmpty()) return null + val sortedCandidates = candidates.sortedBy { + stringDistance(path.joinToString(File.separator), it.toNioPath().toFile().absolutePath) + } + return sortedCandidates.first() + } + + fun update(statusBar: StatusBar, current: AbstractProjectViewPane) { + val paths = current.selectionPaths + val pathChildren = paths?.associate { path -> + path to current.tree.model.getChildCount(path.lastPathComponent) + } ?: emptyMap() + update(statusBar) { + paths?.flatMap { path -> + val childCount = pathChildren[path] ?: 0 + if (0 == childCount) { + /* File */ + val node = path.lastPathComponent + val virtualFile = ProjectManager.getInstance().openProjects.flatMap { + val basePath = it.basePath + if (basePath == null) emptyList() + else com.intellij.openapi.vfs.VirtualFileManager.getInstance() + .findFileByNioPath(java.nio.file.Paths.get(basePath)) + ?.listChildrenRecursively { file -> + file.isFile && file.name.contains(node.toString()) + } ?: emptyList() + }.let { files -> + resolve( + path?.path?.map { it.toString() }?.toTypedArray() ?: emptyArray(), + files + ) + } + listOf(virtualFile?.readText() to node.toString()) + } else { + /* Directory */ + val node = path.lastPathComponent + val virtualFile = ProjectManager.getInstance().openProjects.flatMap { + val basePath = it.basePath + if (basePath == null) emptyList() + else com.intellij.openapi.vfs.VirtualFileManager.getInstance() + .findFileByNioPath(java.nio.file.Paths.get(basePath)) + ?.listChildrenRecursively { file -> + file.isDirectory && file.name.contains(node.toString()) + } ?: emptyList() + }.let { files -> + resolve( + path?.path?.map { it.toString() }?.toTypedArray() ?: emptyArray(), + files + ) + } + val pairs: List> = virtualFile?.listChildrenRecursively { file -> + file.isFile && isLLMIncludableFile(file.toNioPath().toFile()) + }?.map { file -> + file.readText() to file.name + }?.toList() ?: emptyList() + pairs + } + }?.let { pairs -> + val tokenCountCache = mutableMapOf() + fun getCachedTokenCount(text: String): Int = tokenCountCache.getOrPut(text) { codex.estimateTokenCount(text) } + val totalCount = pairs.sumBy { (content, _) -> content?.let { getCachedTokenCount(it) } ?: 0 } + val details = buildString { + //Language=HTML + append("") + append("") + append("") + var totalCount = 0 + for ((content, name) in pairs.sortedBy { + -(it.first?.length ?: 0) + }) { + if (content != null) { + val fileTokens = getCachedTokenCount(content) + append( + "" + ) + totalCount += 1 + } + if (totalCount > 10) { + append("") + break + } + } + append("
FileTokens
$name${ + tokenCountToString( + fileTokens + ) + }
...
") + append("") + } + updateTooltip(details, totalCount) + totalCount + } ?: 0 + } + } + + override fun install(statusBar: StatusBar) { + val connection = statusBar.project?.messageBus?.connect() + connection?.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, object : FileEditorManagerListener { + override fun selectionChanged(event: FileEditorManagerEvent) { + update(statusBar) { + codex.estimateTokenCount((event.newFile ?: event.oldFile)?.readText() ?: "") + updateTooltip(event.newFile?.name ?: event.oldFile?.name, tokenCount) + tokenCount + } + + val editor = FileEditorManager.getInstance(statusBar.project!!).selectedTextEditor + editor?.document?.addDocumentListener(object : DocumentListener { + override fun documentChanged(event: DocumentEvent) { + update(statusBar) { + val count = codex.estimateTokenCount(editor.document.text) + updateTooltip(editor.virtualFile.name, count) + count + } + } + }) + + editor?.selectionModel?.addSelectionListener(object : SelectionListener { + override fun selectionChanged(event: SelectionEvent) { + update(statusBar) { + val newTokens = event.newRanges?.sumOf { + val estimateTokenCount = codex.estimateTokenCount( + event.editor.document.text.substring( + it.startOffset, + it.endOffset + ) + ) + updateTooltip(editor.virtualFile.name, estimateTokenCount) + estimateTokenCount + } ?: 0 + newTokens + } + } + }) + } + }) + connection?.subscribe(ProjectViewListener.TOPIC, object : ProjectViewListener { + var previousSelectionListener: TreeSelectionListener? = null + override fun paneShown(current: AbstractProjectViewPane, previous: AbstractProjectViewPane?) { + val currentSelectionListener = object : TreeSelectionListener { + override fun valueChanged(e: TreeSelectionEvent?) { + update(statusBar, current) + } + } + current.tree.addTreeSelectionListener(currentSelectionListener) + previousSelectionListener?.let { previous?.tree?.removeTreeSelectionListener(it) } + previousSelectionListener = currentSelectionListener + super.paneShown(current, previous) + } + }) + statusBar.project?.let { project -> + val projectView = com.intellij.ide.projectView.impl.ProjectViewImpl.getInstance(project) + val currentPane = projectView.currentProjectViewPane + if (currentPane != null) { + val listener = object : TreeSelectionListener { + override fun valueChanged(e: TreeSelectionEvent?) { + update(statusBar, currentPane) + } + } + currentPane.tree.addTreeSelectionListener(listener) + } + } + } + + private fun updateTooltip(source: String?, count: Int) { + tooltipDetails = when { + source == null -> "No file selected" + source.startsWith("") -> source + else -> "File: $source
Tokens: $count" + } + } + + private fun update(statusBar: StatusBar, tokens: () -> Int) { + workQueue.clear() + isCalculating = true + statusBar.updateWidget(ID()) + pool.submit { + val text = statusBar.project?.let { + FileEditorManager.getInstance(it).selectedTextEditor?.document?.text + } ?: "" + tokenCount = if (text.length > 1024 * 1024) { + -text.length // Using negative value to indicate character count + } else { + tokens() + } + isCalculating = false + statusBar.updateWidget(ID()) + } + } + + override fun dispose() { + //connection?.disconnect() + } + + + override fun getText(): String { + return if (isCalculating) { + val dots = ".".repeat((animationCounter % 3) + 1) + getMessage("status.calculating", dots) + } else { + tokenCountToString(tokenCount) + } + } + + override fun getTooltipText(): String { + return if (isCalculating) { + // Create smooth animated progress indicator + val frames = listOf("⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏") + val spinnerChar = frames[animationCounter % frames.size] + + animationCounter++ + // Reset counter to prevent potential integer overflow + if (animationCounter >= frames.size) animationCounter = 0 + + getMessage("tooltip.calculating_html", spinnerChar) + } else { + // Reset animation counter when not calculating + animationCounter = 0 + tooltipDetails + } + } + + override fun getAlignment(): Float { + return 0.5f + } + + override fun getClickConsumer(): com.intellij.util.Consumer? = null + + companion object { + fun stringDistance(s1: String, s2: String): Int { + val m = s1.length + val n = s2.length + val dp = Array(m + 1) { IntArray(n + 1) } + for (i in 0..m) { + for (j in 0..n) { + when { + i == 0 -> dp[i][j] = j + j == 0 -> dp[i][j] = i + s1[i - 1] == s2[j - 1] -> dp[i][j] = dp[i - 1][j - 1] + else -> dp[i][j] = 1 + minOf(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + } + } + } + return dp[m][n] + } + + fun tokenCountToString(count: Int): String { + return when { + count < 0 -> "${-count} Chars" // Handle character count case + count == 0 -> getMessage("count.zero") + count == 1 -> getMessage("count.one") + count < 0 -> getMessage("count.chars", -count) + count >= 1000000 -> getMessage("count.millions", count / 1000000) + count >= 10000 -> getMessage("count.thousands", count / 1000) + else -> getMessage("count.normal", count) + } + } + } + + + } + + override fun getId(): String { + return "StatusBarComponent" + } + + override fun getDisplayName(): String { + return getMessage("widget.display_name") + } + + override fun createWidget(project: Project, scope: CoroutineScope): StatusBarWidget { + return TokenCountWidget() + } + + override fun createWidget(project: Project): StatusBarWidget { + return TokenCountWidget() + } + + override fun isAvailable(project: Project): Boolean { + return true + } + + override fun canBeEnabledOn(statusBar: StatusBar): Boolean { + return true + } +} + +private fun VirtualFile.listChildrenRecursively(filter: (VirtualFile) -> Boolean): List { + val result = mutableListOf() + fun VirtualFile.listChildrenRecursively() { + when { + isGitignore(this.toNioPath()) -> return + name.startsWith(".") -> return + else -> { + if (filter(this)) result.add(this) + children.forEach { it.listChildrenRecursively() } + } + } + } + listChildrenRecursively() + return result +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/BgTask.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/BgTask.kt new file mode 100644 index 00000000..72df5d69 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/BgTask.kt @@ -0,0 +1,144 @@ +package com.simiacryptus.aicoder.util + +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.Task +import com.intellij.openapi.project.Project +import org.slf4j.LoggerFactory +import java.util.* +import java.util.concurrent.Semaphore +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicReference +import java.util.function.Supplier + +class BgTask( + project: Project, title: String, canBeCancelled: Boolean, val task: (ProgressIndicator) -> T +) : Task.Backgroundable(project, title, canBeCancelled, DEAF), Supplier { + private val taskLog = LoggerFactory.getLogger(BgTask::class.java) + + private val result = AtomicReference() + private val isError = AtomicBoolean(false) + private val error = AtomicReference() + private val startSemaphore = Semaphore(0) + private val completeSemaphore = Semaphore(0) + private val completed = AtomicBoolean(false) + private val threadList = Collections.synchronizedList(ArrayList()) + private val cancelled = AtomicBoolean(false) + private val started = AtomicBoolean(false) + private val lock = Object() + + override fun run(indicator: ProgressIndicator) { + taskLog.debug("Starting run() for BgTask: $title") + synchronized(lock) { + taskLog.debug("Checking task state - started: ${started.get()}, completed: ${completed.get()}, cancelled: ${cancelled.get()}") + if (!started.compareAndSet(false, true)) return + if (completed.get() || cancelled.get()) { + taskLog.debug("Task already completed or cancelled, releasing semaphore") + startSemaphore.release() + completeSemaphore.release() + return + } + } + startSemaphore.release() + val currentThread = Thread.currentThread() + taskLog.debug("Adding thread ${currentThread.name} to threadList") + threadList.add(currentThread) + val scheduledFuture = UITools.scheduledPool.scheduleAtFixedRate({ + if (indicator.isCanceled) { + taskLog.debug("Indicator cancelled, interrupting threads") + cancelled.set(true) + threadList.forEach { it.interrupt() } + } + }, 0, 1, TimeUnit.SECONDS) + try { + synchronized(lock) { + if (completed.get() || cancelled.get()) { + taskLog.debug("Task completed or cancelled during execution") + completeSemaphore.release() + return + } + } + taskLog.debug("Executing task") + val result = task(indicator) + this.result.set(result) + taskLog.debug("Task completed successfully") + } catch (e: Throwable) { + taskLog.error("Error executing task", e) + log.info("Error running task", e) + error.set(e) + isError.set(true) + } finally { + synchronized(lock) { + taskLog.debug("Finalizing task execution") + completed.set(true) + completeSemaphore.release() + } + taskLog.debug("Removing thread ${currentThread.name} from threadList") + threadList.remove(currentThread) + scheduledFuture.cancel(true) + } + } + + override fun get(): T { + taskLog.debug("Attempting to get task result") + try { + // Wait for task to start + val startAcquired = startSemaphore.tryAcquire(5, TimeUnit.SECONDS) + taskLog.debug("Start semaphore acquired: $startAcquired") + synchronized(lock) { + if (!started.get() || !startAcquired) { + taskLog.error("Task timed out or never started") + cancelled.set(true) + throw TimeoutException("Task failed to start after 5 seconds") + } + } + // Wait for task to complete + val completeAcquired = completeSemaphore.tryAcquire(3000, TimeUnit.SECONDS) + taskLog.debug("Complete semaphore acquired: $completeAcquired") + if (!completeAcquired) { + taskLog.error("Task execution timed out") + cancelled.set(true) + throw TimeoutException("Task execution timed out after 30 seconds") + } + } finally { + startSemaphore.release() + completeSemaphore.release() + } + synchronized(lock) { + taskLog.debug("Checking final task state - completed: ${completed.get()}, error: ${isError.get()}, cancelled: ${cancelled.get()}") + if (!completed.get()) { + throw IllegalStateException( + "Task not completed" + + (if (cancelled.get()) " (cancelled)" else "") + ) + } + if (isError.get()) { + val e = error.get() ?: RuntimeException("Unknown error occurred") + taskLog.error("Task failed with error", e) + throw e + } + if (cancelled.get()) { + taskLog.debug("Task was cancelled") + throw InterruptedException("Task was cancelled") + } + taskLog.debug("Returning successful task result") + return result.get() ?: throw IllegalStateException("No result available") + } + } + + override fun onCancel() { + taskLog.debug("Task cancelled") + super.onCancel() + synchronized(lock) { + cancelled.set(true) + threadList.forEach { it.interrupt() } + startSemaphore.release() + completeSemaphore.release() + } + } + + companion object { + private val log = LoggerFactory.getLogger(BgTask::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/BlockComment.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/BlockComment.kt new file mode 100644 index 00000000..6defd78a --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/BlockComment.kt @@ -0,0 +1,57 @@ +@file:Suppress("NAME_SHADOWING") + +package com.simiacryptus.aicoder.util + +import com.simiacryptus.aicoder.util.TextBlock.Companion.DELIMITER +import com.simiacryptus.aicoder.util.TextBlock.Companion.TAB_REPLACEMENT +import com.simiacryptus.util.StringUtil +import java.util.* +import java.util.stream.Collectors + +class BlockComment( + private val blockPrefix: CharSequence, + private val linePrefix: CharSequence, + private val blockSuffix: CharSequence, + indent: CharSequence, + vararg textBlock: CharSequence +) : + IndentedText(indent, *textBlock) { + class Factory(private val blockPrefix: String, private val linePrefix: String, private val blockSuffix: String) : + TextBlockFactory { + override fun fromString(text: String?): BlockComment { + var text = text!! + text = StringUtil.stripSuffix( + StringUtil.trimSuffix(text.replace("\t", TAB_REPLACEMENT.toString(), false)), + blockSuffix.trim { it <= ' ' }) + val indent = StringUtil.getWhitespacePrefix(*text.split(DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray()) + return BlockComment( + blockPrefix, + linePrefix, + blockSuffix, + indent, + *(Arrays.stream(text.split(DELIMITER.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) + .map { s: CharSequence? -> StringUtil.stripPrefix(s!!, indent) } + .map { text: CharSequence? -> StringUtil.trimPrefix(text!!) } + .map { s: CharSequence? -> StringUtil.stripPrefix(s!!, blockPrefix.trim { it <= ' ' }) } + .map { s: CharSequence? -> StringUtil.stripPrefix(s!!, linePrefix.trim { it <= ' ' }) } + .collect(Collectors.toList()).toTypedArray())) + } + + override fun looksLike(text: String?): Boolean { + return text!!.trim { it <= ' ' }.startsWith(blockPrefix) && text.trim { it <= ' ' }.endsWith(blockSuffix) + } + } + + override fun toString(): String { + val indent = this.indent + val delimiter: CharSequence = DELIMITER + indent + val joined: CharSequence = Arrays.stream(rawString()).map { x: CharSequence -> "$linePrefix $x" } + .collect(Collectors.joining(delimiter)) + return blockPrefix.toString() + delimiter + joined + delimiter + blockSuffix + } + + override fun withIndent(indent: CharSequence): IndentedText { + return BlockComment(blockPrefix, linePrefix, blockSuffix, indent, *lines) + } +} diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/BrowseUtil.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/BrowseUtil.kt new file mode 100644 index 00000000..df0bda70 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/BrowseUtil.kt @@ -0,0 +1,43 @@ +package com.simiacryptus.aicoder.util + +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.ui.SettingsWidgetFactory.SettingsWidget +import org.slf4j.LoggerFactory +import java.awt.Desktop +import java.net.DatagramPacket +import java.net.DatagramSocket +import java.net.InetAddress +import java.net.URI + +object BrowseUtil { + + fun browse(uri: URI) { + SettingsWidget().updateSessionsList() + sendUdpMessage(uri.toString()) + if (!AppSettingsState.instance.disableAutoOpenUrls && Desktop.isDesktopSupported()) { + val desktop = Desktop.getDesktop() + if (desktop.isSupported(Desktop.Action.BROWSE)) { + desktop.browse(uri) + } + } + } + + var NOTIFICATION_PORT: Int? = 41390 + private fun sendUdpMessage(message: String) { + try { + log.info("Sending UDP message: $message") + val address = InetAddress.getByName("localhost") + val buf = message.toByteArray() + val packet = DatagramPacket(buf, buf.size, address, NOTIFICATION_PORT ?: return) + val socket = DatagramSocket() + socket.send(packet) + socket.close() + } catch (e: Exception) { + log.warn("Error sending UDP message", e) + } + } + + val log = LoggerFactory.getLogger(BrowseUtil::class.java) + + +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/CodeChatSocketManager.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/CodeChatSocketManager.kt new file mode 100644 index 00000000..d91a1c45 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/CodeChatSocketManager.kt @@ -0,0 +1,45 @@ +package com.simiacryptus.aicoder.util + +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.StorageInterface +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.skyenet.webui.application.ApplicationServer +import com.simiacryptus.skyenet.webui.chat.ChatSocketManager + +open class CodeChatSocketManager( + session: Session, + val language: String, + val filename: String, + val codeSelection: String, + api: ChatClient, + model: ChatModel, + storage: StorageInterface?, +) : ChatSocketManager( + session = session, + model = model, + userInterfacePrompt = (""" + # `""".trimIndent() + filename + """` + + ```""".trimIndent() + language + """ + """.trimIndent() + codeSelection + """ + ``` + """.trimIndent()).trim(), + systemPrompt = """ + You are a helpful AI that helps people with coding. + + You will be answering questions about the following code located in `""" + filename + """`: + + ```""".trimIndent() + language + """ + """.trimIndent() + codeSelection + """ + ``` + + Responses may use markdown formatting, including code blocks. + """.trimIndent(), + api = api, + applicationClass = ApplicationServer::class.java, + storage = storage, +) { + override fun canWrite(user: User?): Boolean = true +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/ComputerLanguage.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/ComputerLanguage.kt new file mode 100644 index 00000000..8826ef49 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/ComputerLanguage.kt @@ -0,0 +1,483 @@ +package com.simiacryptus.aicoder.util + +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import java.util.* + +enum class ComputerLanguage(configuration: Configuration) { + Java( + Configuration() + .setDocumentationStyle("JavaDoc") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", " * ", " */")) + .setFileExtensions("java") + ), + Cpp( + Configuration() + .setDocumentationStyle("Doxygen") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("cpp") + ), + LUA( + Configuration() + .setDocumentationStyle("LuaDoc") + .setLineComments(LineComment.Factory("--")) + .setBlockComments(BlockComment.Factory("--[[", "", "]]")) + .setDocComments(BlockComment.Factory("---[[", "", "]]")) + .setFileExtensions("lua") + ), + SVG( + Configuration() + .setDocumentationStyle("SVG") + .setLineComments(LineComment.Factory("")) + .setDocComments(BlockComment.Factory("")) + .setFileExtensions("svg") + ), + OpenSCAD( + Configuration() + .setDocumentationStyle("OpenSCAD") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("scad") + ), + Bash( + Configuration() + .setLineComments(LineComment.Factory("#")) + .setFileExtensions("sh") + ), + Markdown( + Configuration() + .setDocumentationStyle("Markdown") + .setLineComments(BlockComment.Factory("")) + .setBlockComments(BlockComment.Factory("")) + .setDocComments(BlockComment.Factory("")) + .setFileExtensions("md") + ), + Text( + Configuration() + .setDocumentationStyle("Text") + .setLineComments(LineComment.Factory("#")) + .setFileExtensions("txt") + ), + XML( + Configuration() + .setDocumentationStyle("XML") + .setLineComments(BlockComment.Factory("")) + .setBlockComments(BlockComment.Factory("")) + .setDocComments(BlockComment.Factory("")) + .setFileExtensions("xml") + ), + Ada( + Configuration() + .setLineComments(LineComment.Factory("--")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("ada") + ), + Assembly( + Configuration() + .setLineComments(LineComment.Factory(";")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("assembly", "asm") + ), + Basic( + Configuration() + .setLineComments(LineComment.Factory("'")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("basic", "bs") + ), + C( + Configuration() + .setDocumentationStyle("Doxygen") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("c") + ), + Clojure( + Configuration() + .setDocumentationStyle("ClojureDocs") + .setLineComments(LineComment.Factory(";")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("cj") + ), + COBOL( + Configuration() + .setLineComments(LineComment.Factory("*")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("cobol", "cob") + ), + CSharp( + Configuration() + .setDocumentationStyle("XML") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("cs", "c#") + ), + CSS( + Configuration() + .setLineComments(BlockComment.Factory("/*", "", "*/")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("css") + ), + Dart( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("dart") + ), + Delphi( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("delphi") + ), + Erlang( + Configuration() + .setLineComments(LineComment.Factory("%")) + .setBlockComments(BlockComment.Factory("%%", "", "%%")) + .setDocComments(BlockComment.Factory("%%%", "%", "%%%")) + .setFileExtensions("erl") + ), + Elixir( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("elixir") + ), + FORTRAN( + Configuration() + .setLineComments(LineComment.Factory("!")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("f", "for", "ftn", "f77", "f90", "f95", "f03", "f08") + ), + FSharp( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("f#") + ), + Go( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("go") + ), + Groovy( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("groovy", "gradle") + ), + Haskell( + Configuration() + .setLineComments(LineComment.Factory("--")) + .setBlockComments(BlockComment.Factory("{-", "-}", "{- -}")) + .setDocComments(BlockComment.Factory("{-|", "|-}", "{-| -}")) + .setFileExtensions("hs") + ), + HTML( + Configuration() + .setLineComments(BlockComment.Factory("")) + .setBlockComments(BlockComment.Factory("")) + .setDocComments(BlockComment.Factory("")) + .setFileExtensions("html") + ), + Julia( + Configuration() + .setLineComments(LineComment.Factory("#")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("julia") + ), + JavaScript( + Configuration() + .setDocumentationStyle("JSDoc") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("js", "javascript") + ), + Json( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setFileExtensions("json") + ), + Kotlin( + Configuration() + .setDocumentationStyle("KDoc") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("kt", "kts") + ), + Lisp( + Configuration() + .setLineComments(LineComment.Factory(";")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("lisp") + ), + Logo( + Configuration() + .setLineComments(LineComment.Factory(";")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("logo", "log") + ), + MATLAB( + Configuration() + .setLineComments(LineComment.Factory("%")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("matlab", "m") + ), + OCaml( + Configuration() + .setLineComments(LineComment.Factory("(Params.create(*")) + .setBlockComments(BlockComment.Factory("*))", "", "ocaml")) + .setDocComments(BlockComment.Factory("*))", "", "ocaml")) + .setFileExtensions("ml") + ), + Pascal( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("pascal", "pas") + ), + PHP( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("php") + ), + Perl( + Configuration() + .setDocumentationStyle("POD") + .setLineComments(LineComment.Factory("#")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("perl", "pl") + ), + Prolog( + Configuration() + .setLineComments(LineComment.Factory("%")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("prolog") + ), + Python( + Configuration() + .setDocumentationStyle("PyDoc") + .setLineComments(LineComment.Factory("#")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("py", "python") + ), + R( + Configuration() + .setLineComments(LineComment.Factory("#")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("r") + ), + Ruby( + Configuration() + .setLineComments(LineComment.Factory("#")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("ruby", "rb") + ), + Racket( + Configuration() + .setLineComments(LineComment.Factory("#")) + .setBlockComments(BlockComment.Factory("#|", "", "|#")) + .setDocComments(BlockComment.Factory("#|", "", "|#")) + .setFileExtensions("racket") + ), + Rust( + Configuration() + .setDocumentationStyle("Rustdoc") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("rs", "rust") + ), + Scala( + Configuration() + .setDocumentationStyle("ScalaDoc") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("scala", "sc") + ), + Scheme( + Configuration() + .setLineComments(LineComment.Factory(";")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("scheme") + ), + SCSS( + Configuration() + .setDocumentationStyle("SCSS") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(LineComment.Factory("///")) + .setFileExtensions("scss") + ), + SQL( + Configuration() + .setLineComments(LineComment.Factory("--")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("sql") + ), + Smalltalk( + Configuration() + .setLineComments(LineComment.Factory("\"")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("smalltalk", "st") + ), + Swift( + Configuration() + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("swift") + ), + Tcl( + Configuration() + .setLineComments(LineComment.Factory("#")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("tcl") + ), + TypeScript( + Configuration() + .setDocumentationStyle("TypeDoc") + .setLineComments(LineComment.Factory("//")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("typescript", "ts") + ), + VisualBasic( + Configuration() + .setLineComments(LineComment.Factory("'")) + .setBlockComments(BlockComment.Factory("/*", "", "*/")) + .setDocComments(BlockComment.Factory("/**", "*", "*/")) + .setFileExtensions("visualbasic", "vb") + ), + YAML( + Configuration() + .setLineComments(LineComment.Factory("#")) + .setFileExtensions("yaml") + ), + ZShell( + Configuration() + .setLineComments(LineComment.Factory("#")) + .setFileExtensions("zsh") + ); + + val extensions: List + val docStyle: String + val lineComment: TextBlockFactory<*> + val blockComment: TextBlockFactory<*> + private val docComment: TextBlockFactory<*> + + init { + extensions = listOf(*configuration.fileExtensions) + docStyle = configuration.documentationStyle + lineComment = configuration.lineComments!! + blockComment = configuration.getBlockComments()!! + docComment = configuration.getDocComments()!! + } + + fun getCommentModel(text: String?): TextBlockFactory<*> { + if (Objects.requireNonNull(docComment)!!.looksLike(text)) return docComment + return if (Objects.requireNonNull(blockComment)!!.looksLike(text)) blockComment else lineComment + } + + internal class Configuration { + var documentationStyle = "" + private set + var fileExtensions = arrayOf() + private set + var lineComments: TextBlockFactory<*>? = null + private set + private var blockComments: TextBlockFactory<*>? = null + private var docComments: TextBlockFactory<*>? = null + fun setDocumentationStyle(documentationStyle: String): Configuration { + this.documentationStyle = documentationStyle + return this + } + + fun setFileExtensions(vararg fileExtensions: CharSequence): Configuration { + @Suppress("UNCHECKED_CAST") + this.fileExtensions = fileExtensions as Array + return this + } + + fun setLineComments(lineComments: TextBlockFactory<*>): Configuration { + this.lineComments = lineComments + return this + } + + fun getBlockComments(): TextBlockFactory<*>? { + return if (null == blockComments) lineComments else blockComments + } + + fun setBlockComments(blockComments: TextBlockFactory<*>): Configuration { + this.blockComments = blockComments + return this + } + + fun getDocComments(): TextBlockFactory<*>? { + return if (null == docComments) getBlockComments() else docComments + } + + fun setDocComments(docComments: TextBlockFactory<*>): Configuration { + this.docComments = docComments + return this + } + } + + companion object { + @JvmStatic + fun findByExtension(extension: CharSequence): ComputerLanguage? { + return Arrays.stream(values()).filter { x: ComputerLanguage -> + x.extensions.contains( + extension + ) + }.findAny().orElse(null) + } + + @JvmStatic + fun getComputerLanguage(e: AnActionEvent?): ComputerLanguage? { + val file = e?.getData(CommonDataKeys.VIRTUAL_FILE) ?: return null + val extension = if (file.extension != null) file.extension!!.lowercase(Locale.getDefault()) else "" + return findByExtension(extension) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/FileUtils.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/FileUtils.kt new file mode 100644 index 00000000..2dbee093 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/FileUtils.kt @@ -0,0 +1,19 @@ +package com.simiacryptus.aicoder.util + +import com.intellij.openapi.vfs.VirtualFile + +fun VirtualFile.findRecursively(predicate: (VirtualFile) -> Boolean): List { + val results = mutableListOf() + if (this.isDirectory) { + this.children?.forEach { child -> + if (child.isDirectory) { + results.addAll(child.findRecursively(predicate)) + } else if (predicate(child)) { + results.add(child) + } + } + } else if (predicate(this)) { + results.add(this) + } + return results +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/IdeaChatClient.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/IdeaChatClient.kt new file mode 100644 index 00000000..03bf9fe8 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/IdeaChatClient.kt @@ -0,0 +1,233 @@ +package com.simiacryptus.aicoder.util + +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.ui.components.JBScrollPane +import com.intellij.util.ui.FormBuilder +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.jopenai.ChatClient +import com.simiacryptus.jopenai.models.APIProvider +import com.simiacryptus.jopenai.models.ApiModel.* +import com.simiacryptus.jopenai.models.OpenAIModel +import com.simiacryptus.jopenai.models.TextModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.model.User +import com.simiacryptus.util.JsonUtil +import com.simiacryptus.util.JsonUtil.toJson +import org.apache.hc.core5.http.HttpRequest +import org.slf4j.LoggerFactory +import org.slf4j.event.Level +import java.io.File +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicReference +import javax.swing.JPanel +import javax.swing.JTextArea + + +open class IdeaChatClient( + key: Map = AppSettingsState.instance.apiKey?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() + ?.associate { it.key to it.value } ?: mapOf(), + apiBase: Map = AppSettingsState.instance.apiBase?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() + ?.associate { it.key to it.value } ?: mapOf(), +) : ChatClient( + key = key, + apiBase = apiBase, +) { + + init { + //log.info("Initializing OpenAI Client", Throwable()) + require(key.size == apiBase.size) { + "API Key not configured for all providers: ${key.keys} != ${APIProvider.values().toList()}" + } + } + + private class IdeaChildClient( + val inner: IdeaChatClient, + key: Map, + apiBase: Map + ) : IdeaChatClient( + key = key, + apiBase = apiBase + ) { + override fun log(level: Level, msg: String) { + super.log(level, msg) + inner.log(level, msg) + } + } + + override fun getChildClient(): ChatClient = IdeaChildClient(inner = this, key = key, apiBase = apiBase).apply { + session = inner.session + user = inner.user + } + + private val isInRequest = AtomicBoolean(false) + + override fun onUsage(model: OpenAIModel?, tokens: Usage) { +// AppSettingsState.instance.tokenCounter += tokens.total_tokens + ApplicationServices.usageManager.incrementUsage(currentSession, localUser, model!!, tokens) + } + + override fun authorize(request: HttpRequest, apiProvider: APIProvider) { + val checkApiKey = key.get(apiProvider) ?: throw IllegalArgumentException("No API Key for $apiProvider") + key = key.toMutableMap().let { + it[apiProvider] = checkApiKey + it + }.entries.toTypedArray().associate { it.key to it.value } + super.authorize(request, apiProvider) + } + + @Suppress("NAME_SHADOWING") + override fun chat( + chatRequest: ChatRequest, + model: TextModel + ): ChatResponse { + val storeMetadata = AppSettingsState.instance.storeMetadata + var chatRequest = chatRequest.copy( + store = storeMetadata?.let { it.isNotBlank() }, + metadata = storeMetadata?.let { JsonUtil.fromJson(it, Map::class.java) } + ) + val lastEvent = lastEvent + lastEvent ?: return super.chat(chatRequest, model) + chatRequest = chatRequest.copy( + store = chatRequest.store, + metadata = chatRequest.metadata?.let { + it + mapOf( + "project" to lastEvent.project?.name, + "action" to lastEvent.presentation.text, + "language" to lastEvent.getData(CommonDataKeys.PSI_FILE)?.language?.displayName, + ) + } + ) + if (isInRequest.getAndSet(true)) { + val response = super.chat(chatRequest, model) + if (null != response.usage) { + UITools.logAction( + "Chat Response: ${toJson(response.usage!!)}" + ) + } + return response + } else { + try { + if (!AppSettingsState.instance.editRequests) { + val response = super.chat(chatRequest, model) + if (null != response.usage) { + UITools.logAction( + "Chat Response: ${toJson(response.usage!!)}" + ) + } + return response + } + return withJsonDialog(chatRequest, { chatRequest -> + UITools.run( + lastEvent.project, "OpenAI Request", true, suppressProgress = false + ) { + val response = super.chat(chatRequest, model) + if (null != response.usage) { + UITools.logAction( + "Chat Response: ${toJson(response.usage!!)}".trim() + ) + } + response + } + }, "Edit Chat Request") + } finally { + isInRequest.set(false) + } + } + } + + + companion object { + + val instance by lazy { + //log.info("Initializing OpenAI Client", Throwable()) + val client = IdeaChatClient() + if (AppSettingsState.instance.apiLog) { + try { + val file = File(AppSettingsState.instance.pluginHome, "openai.log") + file.parentFile.mkdirs() + AppSettingsState.auxiliaryLog = file + client.logStreams.add(java.io.FileOutputStream(file, file.exists()).buffered()) + } catch (e: Exception) { + log.warn("Error initializing log file", e) + } + } + client + } + + var lastEvent: AnActionEvent? = null + private fun uiEdit( + project: Project? = null, + title: String = "Edit Request", + jsonTxt: String + ): String { + return execute { + val json = JTextArea( + /* text = */ "", + /* rows = */ 3, + /* columns = */ 120 + ) + json.isEditable = true + json.lineWrap = false + val jbScrollPane = JBScrollPane(json) + jbScrollPane.horizontalScrollBarPolicy = JBScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED + jbScrollPane.verticalScrollBarPolicy = JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED + val dialog = object : DialogWrapper(project) { + init { + this.init() + this.title = title + this.setOKButtonText("OK") + this.setCancelButtonText("Cancel") + this.isResizable = true + } + + override fun createCenterPanel(): JPanel? { + val formBuilder = FormBuilder.createFormBuilder() + formBuilder.addLabeledComponentFillVertically("JSON", jbScrollPane) + return formBuilder.panel + } + } + json.text = jsonTxt + dialog.show() + log.warn("dialog.size = " + dialog.size) + if (!dialog.isOK) { + throw RuntimeException("Cancelled") + } + json.text + } ?: jsonTxt + } + + private fun execute( + fn: () -> T + ): T? { + val application = ApplicationManager.getApplication() + val ref: AtomicReference = AtomicReference() + if (null != application) { + application.invokeAndWait { ref.set(fn()) } + } else { + ref.set(fn()) + } + return ref.get() + } + + + fun withJsonDialog( + request: T, + function: (T) -> V, + title: String + ): V { + val project = lastEvent?.project ?: return function(request) + return function(JsonUtil.fromJson(uiEdit(project, title, toJson(request)), request::class.java)) + } + + private val log = LoggerFactory.getLogger(IdeaChatClient::class.java) + val currentSession = Session.newGlobalID() + val localUser = User(id = "1", email = "user@localhost") + } + +} + diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/IdeaOpenAIClient.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/IdeaOpenAIClient.kt new file mode 100644 index 00000000..f586fb14 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/IdeaOpenAIClient.kt @@ -0,0 +1,64 @@ +package com.simiacryptus.aicoder.util + +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.jopenai.OpenAIClient +import com.simiacryptus.jopenai.models.APIProvider +import com.simiacryptus.jopenai.models.ApiModel +import com.simiacryptus.jopenai.models.OpenAIModel +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import org.apache.hc.core5.http.HttpRequest +import org.slf4j.LoggerFactory +import java.io.File + +class IdeaOpenAIClient : OpenAIClient( + key = AppSettingsState.instance.apiKey?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() + ?.associate { it.key to it.value } ?: mapOf(), + apiBase = AppSettingsState.instance.apiBase?.mapKeys { APIProvider.valueOf(it.key) }?.entries?.toTypedArray() + ?.associate { it.key to it.value } ?: mapOf(), +) { + + init { + //log.info("Initializing OpenAI Client", Throwable()) + require(key.size == apiBase.size) { + "API Key not configured for all providers: ${key.keys} != ${APIProvider.values().toList()}" + } + } + + override fun onUsage(model: OpenAIModel?, tokens: ApiModel.Usage) { +// AppSettingsState.instance.tokenCounter += tokens.total_tokens + ApplicationServices.usageManager.incrementUsage( + IdeaChatClient.currentSession, + IdeaChatClient.localUser, model!!, tokens + ) + } + + override fun authorize(request: HttpRequest, apiProvider: APIProvider) { + val checkApiKey = + key.get(apiProvider) ?: throw IllegalArgumentException("No API Key for $apiProvider") + key = key.toMutableMap().let { + it[apiProvider] = checkApiKey + it + }.entries.toTypedArray().associate { it.key to it.value } + super.authorize(request, apiProvider) + } + + companion object { + + val instance by lazy { + //log.info("Initializing OpenAI Client", Throwable()) + val client = IdeaOpenAIClient() + if (AppSettingsState.instance.apiLog) { + try { + val file = File(AppSettingsState.instance.pluginHome, "openai.log") + file.parentFile.mkdirs() + AppSettingsState.auxiliaryLog = file + client.logStreams.add(java.io.FileOutputStream(file, file.exists()).buffered()) + } catch (e: Exception) { + log.warn("Error initializing log file", e) + } + } + client + } + val log = LoggerFactory.getLogger(IdeaOpenAIClient::class.java) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/IndentedText.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/IndentedText.kt new file mode 100644 index 00000000..27c1e3cc --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/IndentedText.kt @@ -0,0 +1,45 @@ +package com.simiacryptus.aicoder.util + +import com.simiacryptus.util.StringUtil + +/** + * This class provides a way to store and manipulate indented text blocks. + * + * The text block is stored as a single string, with each line separated by a newline character. + * The indentation is stored as a separate string, which is prepended to each line when the text block is converted to a string. + * + * The class provides a companion object method to convert a string to an IndentedText object. + * This method replaces all tab characters with two spaces, and then finds the minimum indentation of all lines. + * This indentation is then used as the indentation for the IndentedText object. + * + * The class also provides a method to create a new IndentedText object with a different indentation. + */ +open class IndentedText(var indent: CharSequence, vararg val lines: CharSequence) : TextBlock { + + override fun toString(): String { + return rawString().joinToString(TextBlock.DELIMITER + indent) + } + + override fun withIndent(indent: CharSequence): IndentedText { + return IndentedText(indent, *lines) + } + + override fun rawString(): Array { + return lines + } + + companion object { + /** + * This method is used to convert a string into an IndentedText object. + * + * @param text The string to be converted into an IndentedText object. + * @return IndentedText object created from the input string. + */ + fun fromString(text: String?): IndentedText { + val processedText = (text ?: "").replace("\t", TextBlock.TAB_REPLACEMENT.toString()) + val lines = processedText.split(TextBlock.DELIMITER) + val indent = StringUtil.getWhitespacePrefix(*lines.toTypedArray()) + return IndentedText(indent, *lines.map { StringUtil.stripPrefix(it, indent) }.toTypedArray()) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/LanguageUtils.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/LanguageUtils.kt new file mode 100644 index 00000000..01779903 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/LanguageUtils.kt @@ -0,0 +1,23 @@ +package com.simiacryptus.aicoder.util + +import aicoder.actions.agent.toFile +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiManager +import java.util.* + +object LanguageUtils { + + fun getComputerLanguage(e: AnActionEvent): ComputerLanguage? { + return ApplicationManager.getApplication().runReadAction { + val editor = e.getData(CommonDataKeys.EDITOR) ?: return@runReadAction null + val virtualFile: VirtualFile = FileDocumentManager.getInstance().getFile(editor.document) ?: return@runReadAction null + val file = PsiManager.getInstance(e.project!!).findFile(virtualFile)?.virtualFile?.toFile ?: return@runReadAction null + val extension = if (file.extension != null) file.extension.lowercase(Locale.getDefault()) else "" + return@runReadAction ComputerLanguage.findByExtension(extension) + } + } +} diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/LineComment.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/LineComment.kt new file mode 100644 index 00000000..c0ff5255 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/LineComment.kt @@ -0,0 +1,56 @@ +package com.simiacryptus.aicoder.util + +import com.simiacryptus.util.StringUtil.getWhitespacePrefix +import com.simiacryptus.util.StringUtil.stripPrefix +import com.simiacryptus.util.StringUtil.trimPrefix +import java.util.* +import java.util.stream.Collectors + +class LineComment(private val commentPrefix: CharSequence, indent: CharSequence?, vararg lines: CharSequence) : + IndentedText(indent!!, *lines) { + class Factory(private val commentPrefix: String) : TextBlockFactory { + override fun fromString(text: String?): LineComment { + var textVar = text + textVar = textVar!!.replace(Regex("\t"), TextBlock.TAB_REPLACEMENT.toString()) + val indent = + getWhitespacePrefix(*textVar.split(TextBlock.DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray()) + return LineComment( + commentPrefix, + indent, + *Arrays.stream(textVar.split(TextBlock.DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray()) + .map { s: String? -> + stripPrefix( + s!!, indent + ) + } + .map { obj: CharSequence -> trimPrefix(obj) } + .map { s: CharSequence? -> + stripPrefix( + s!!, + commentPrefix + ) + } + .collect(Collectors.toList()).toTypedArray()) + } + + override fun looksLike(text: String?): Boolean { + return Arrays.stream(text!!.split(TextBlock.DELIMITER.toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray()).allMatch { x: String -> + x.trim { it <= ' ' }.startsWith( + commentPrefix + ) + } + } + } + + override fun toString(): String { + return "$commentPrefix " + Arrays.stream(rawString()) + .collect(Collectors.joining(TextBlock.DELIMITER + indent + commentPrefix + " ")) + } + + override fun withIndent(indent: CharSequence): LineComment { + return LineComment(commentPrefix, indent, *lines) + } +} diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/ModalTask.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/ModalTask.kt new file mode 100644 index 00000000..e096f72a --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/ModalTask.kt @@ -0,0 +1,131 @@ +package com.simiacryptus.aicoder.util + +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.Task +import com.intellij.openapi.project.Project +import org.slf4j.LoggerFactory +import java.util.* +import java.util.concurrent.Semaphore +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicReference +import java.util.function.Supplier + +class ModalTask( + project: Project, title: String, canBeCancelled: Boolean, val task: (ProgressIndicator) -> T +) : Task.WithResult(project, title, canBeCancelled), Supplier { + private val taskLog = LoggerFactory.getLogger(ModalTask::class.java) + private val result = AtomicReference() + private val isError = AtomicBoolean(false) + private val error = AtomicReference() + private val semaphore = Semaphore(0) + private val completed = AtomicBoolean(false) + private val threadList = Collections.synchronizedList(ArrayList()) + private val cancelled = AtomicBoolean(false) + private val started = AtomicBoolean(false) + private val lock = Object() + + override fun compute(indicator: ProgressIndicator): T? { + taskLog.debug("Starting compute() for ModalTask: $title") + synchronized(lock) { + taskLog.debug("Checking task state - started: ${started.get()}, completed: ${completed.get()}, cancelled: ${cancelled.get()}") + if (!started.compareAndSet(false, true)) return null + if (completed.get() || cancelled.get()) { + taskLog.debug("Task already completed or cancelled, releasing semaphore") + semaphore.release() + return null + } + } + val currentThread = Thread.currentThread() + taskLog.debug("Adding thread ${currentThread.name} to threadList") + threadList.add(currentThread) + val scheduledFuture = UITools.scheduledPool.scheduleAtFixedRate({ + if (indicator.isCanceled) { + taskLog.debug("Indicator cancelled, interrupting threads") + cancelled.set(true) + threadList.forEach { it.interrupt() } + } + }, 0, 1, TimeUnit.SECONDS) + return try { + synchronized(lock) { + if (completed.get() || cancelled.get()) { + taskLog.debug("Task completed or cancelled during execution") + semaphore.release() + return null + } + } + taskLog.debug("Executing task") + result.set(task(indicator)) + taskLog.debug("Task completed successfully") + result.get() + } catch (e: Throwable) { + taskLog.error("Error executing task", e) + log.info("Error running task", e) + isError.set(true) + error.set(e) + null + } finally { + synchronized(lock) { + taskLog.debug("Finalizing task execution") + completed.set(true) + semaphore.release() + } + taskLog.debug("Removing thread ${currentThread.name} from threadList") + threadList.remove(currentThread) + scheduledFuture.cancel(true) + } + } + + override fun get(): T { + taskLog.debug("Attempting to get task result") + try { + val acquired = semaphore.tryAcquire(30, TimeUnit.SECONDS) + taskLog.debug("Semaphore acquired: $acquired") + synchronized(lock) { + if (!started.get() || !acquired) { + taskLog.error("Task timed out or never started") + cancelled.set(true) + throw TimeoutException("Task timed out after 30 seconds") + } + } + } finally { + semaphore.release() + } + synchronized(lock) { + taskLog.debug("Checking final task state - completed: ${completed.get()}, error: ${isError.get()}, cancelled: ${cancelled.get()}") + if (!completed.get()) { + throw IllegalStateException( + "Task not completed" + + (if (cancelled.get()) " (cancelled)" else "") + ) + } + if (isError.get()) { + val e = error.get() ?: RuntimeException("Unknown error occurred") + taskLog.error("Task failed with error", e) + throw e + } + if (cancelled.get()) { + taskLog.debug("Task was cancelled") + throw InterruptedException("Task was cancelled") + } + taskLog.debug("Returning successful task result") + return result.get() ?: throw IllegalStateException("No result available") + } + } + + override fun onCancel() { + taskLog.debug("Task cancelled") + super.onCancel() + synchronized(lock) { + cancelled.set(true) + threadList.forEach { it.interrupt() } + semaphore.release() + } + } + + companion object { + private val log = LoggerFactory.getLogger(ModalTask::class.java) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/PluginStartupActivity.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/PluginStartupActivity.kt new file mode 100644 index 00000000..8b9066ac --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/PluginStartupActivity.kt @@ -0,0 +1,202 @@ +package com.simiacryptus.aicoder.util + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.FileEditorManagerListener +import com.intellij.openapi.fileEditor.TextEditorWithPreview +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.ProjectActivity +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.jopenai.models.ChatModel +import com.simiacryptus.skyenet.core.OutputInterceptor +import com.simiacryptus.skyenet.core.platform.ApplicationServices +import com.simiacryptus.skyenet.core.platform.AwsPlatform +import com.simiacryptus.skyenet.core.platform.ClientManager +import com.simiacryptus.skyenet.core.platform.Session +import com.simiacryptus.skyenet.core.platform.hsql.HSQLUsageManager +import com.simiacryptus.skyenet.core.platform.model.ApplicationServicesConfig +import com.simiacryptus.skyenet.core.platform.model.ApplicationServicesConfig.isLocked +import com.simiacryptus.skyenet.core.platform.model.AuthenticationInterface +import com.simiacryptus.skyenet.core.platform.model.AuthorizationInterface +import com.simiacryptus.skyenet.core.platform.model.User +import org.jetbrains.annotations.NonNls +import software.amazon.awssdk.regions.Region +import java.io.File +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean +import kotlin.reflect.full.declaredMembers +import kotlin.reflect.jvm.isAccessible + +class PluginStartupActivity : ProjectActivity { + private val documentationPageOpenTimes = ConcurrentHashMap() + private lateinit var messageBusConnection: com.intellij.util.messages.MessageBusConnection + override suspend fun execute(project: Project) { + // Check if this is the first run after installation + try { + //ApplicationServicesConfig.dataStorageRoot = ApplicationServicesConfig.dataStorageRoot.resolve("intellij") + val currentThread = Thread.currentThread() + val prevClassLoader = currentThread.contextClassLoader + try { + currentThread.contextClassLoader = PluginStartupActivity::class.java.classLoader + init() + // Add user-supplied models to ChatModel + addUserSuppliedModels(AppSettingsState.instance.userSuppliedModels) + } finally { + currentThread.contextClassLoader = prevClassLoader + } + // Set up file editor listener for documentation tracking + setupDocumentationTracking(project) + + if (AppSettingsState.instance.showWelcomeScreen || AppSettingsState.instance.greetedVersion != AppSettingsState.WELCOME_VERSION) { + val welcomeFile = "welcomePage.md" + val resource = PluginStartupActivity::class.java.classLoader.getResource(welcomeFile) + var virtualFile = resource?.let { VirtualFileManager.getInstance().findFileByUrl(it.toString()) } + if (virtualFile == null) try { + val path = resource?.toURI()?.let { java.nio.file.Paths.get(it) } + virtualFile = path?.let { VirtualFileManager.getInstance().findFileByNioPath(it) } + } catch (e: Exception) { + log.debug("Error opening welcome page", e) + } + if (virtualFile == null) { + try { + val tempFile = + File.createTempFile(welcomeFile.substringBefore("."), "." + welcomeFile.substringAfter(".")) + tempFile.deleteOnExit() + resource?.openStream()?.use { input -> + tempFile.outputStream().use { output -> input.copyTo(output) } + } + virtualFile = VirtualFileManager.getInstance().refreshAndFindFileByNioPath(tempFile.toPath()) + } catch (e: Exception) { + log.error("Error opening welcome page", e) + } + } + virtualFile?.let { + try { + ApplicationManager.getApplication().invokeLater { + FileEditorManager.getInstance(project).openFile(it, true).forEach { editor -> + try { + editor::class.declaredMembers.filter { it.name == "setLayout" }.forEach { member -> + member.isAccessible = true + member.call(editor, TextEditorWithPreview.Layout.SHOW_PREVIEW) + } + } catch (e: Exception) { + log.error("Error opening welcome page", e) + } + } + } + } catch (e: Exception) { + log.error("Error opening welcome page", e) + } + } ?: log.error("Welcome page not found") + // Set showWelcomeScreen to false after showing it for the first time + AppSettingsState.instance.greetedVersion = AppSettingsState.WELCOME_VERSION + AppSettingsState.instance.showWelcomeScreen = false + } + } catch (e: Exception) { + log.error("Error during plugin startup", e) + } + } + + private fun setupDocumentationTracking(project: Project) { + messageBusConnection = project.messageBus.connect() + messageBusConnection.subscribe( + FileEditorManagerListener.FILE_EDITOR_MANAGER, + object : FileEditorManagerListener { + override fun fileOpened(source: FileEditorManager, file: VirtualFile) { + if (isDocumentationFile(file)) { + trackDocumentationPageView(file) + } + } + + override fun fileClosed(source: FileEditorManager, file: VirtualFile) { + if (isDocumentationFile(file)) { + trackDocumentationPageClose(file) + } + } + } + ) + } + + private fun isDocumentationFile(file: VirtualFile): Boolean { + return file.path.contains("/docs/") || file.extension == "md" + } + + private fun trackDocumentationPageView(file: VirtualFile) { + if (AppSettingsState.instance.analyticsEnabled) { + val pagePath = file.path + documentationPageOpenTimes[pagePath] = System.currentTimeMillis() + mapOf("page" to pagePath) + } + } + + private fun trackDocumentationPageClose(file: VirtualFile) { + if (AppSettingsState.instance.analyticsEnabled) { + val pagePath = file.path + val openTime = documentationPageOpenTimes.remove(pagePath) + if (openTime != null) { + val timeSpent = System.currentTimeMillis() - openTime + mapOf( + "page" to pagePath, + "time_spent" to TimeUnit.MILLISECONDS.toSeconds(timeSpent) + ) + } + } + } + + private val isInitialized = AtomicBoolean(false) + + private fun init() { + if (isInitialized.getAndSet(true)) return + ApplicationServicesConfig.dataStorageRoot = AppSettingsState.instance.pluginHome.resolve(".skyenet") + OutputInterceptor.setupInterceptor() + ApplicationServices.clientManager = object : ClientManager() { + override fun createChatClient(session: Session, user: User?) = + IdeaChatClient.instance + } + AppSettingsState.instance.apply { + if (!awsProfile.isNullOrBlank() && !awsRegion.isNullOrBlank() && !awsBucket.isNullOrBlank()) { + ApplicationServices.cloud = AwsPlatform( + bucket = awsBucket!!, + region = Region.of(awsRegion!!), + profileName = awsProfile!!, + ) + } else { + ApplicationServices.cloud = null + } + } + ApplicationServices.usageManager = HSQLUsageManager(ApplicationServicesConfig.dataStorageRoot.resolve("usage")) + ApplicationServices.authorizationManager = object : AuthorizationInterface { + override fun isAuthorized( + applicationClass: Class<*>?, + user: User?, + operationType: AuthorizationInterface.OperationType + ) = true + } + ApplicationServices.authenticationManager = object : AuthenticationInterface { + override fun getUser(accessToken: String?) = null + override fun putUser(accessToken: String, user: User) = user + override fun logout(accessToken: String, user: User) {} + } + isLocked = true + } + + companion object { + val log = org.slf4j.LoggerFactory.getLogger(PluginStartupActivity::class.java) + + fun addUserSuppliedModels(userModels: List) { + userModels.forEach { model -> + ChatModel.values[model.displayName] = ChatModel( + name = model.displayName, + modelName = model.modelId, + maxTotalTokens = 4096, // Default value, adjust as needed + provider = model.provider, + inputTokenPricePerK = 0.0, // Default value, adjust as needed + outputTokenPricePerK = 0.0 // Default value, adjust as needed + ) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/StringUtil.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/StringUtil.kt new file mode 100644 index 00000000..3ffc893d --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/StringUtil.kt @@ -0,0 +1,21 @@ +package com.simiacryptus.aicoder.util + +object StringUtil { + fun lineWrapping(text: String, maxLineLength: Int): String { + val words = text.split(" ") + val lines = mutableListOf() + var currentLine = StringBuilder() + + for (word in words) { + if (currentLine.length + word.length + 1 <= maxLineLength) { + if (currentLine.isNotEmpty()) currentLine.append(" ") + currentLine.append(word) + } else { + if (currentLine.isNotEmpty()) lines.add(currentLine.toString()) + currentLine = StringBuilder(word) + } + } + if (currentLine.isNotEmpty()) lines.add(currentLine.toString()) + return lines.joinToString("\n") + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/TextBlock.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/TextBlock.kt new file mode 100644 index 00000000..84892abb --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/TextBlock.kt @@ -0,0 +1,20 @@ +package com.simiacryptus.aicoder.util + +import java.util.stream.Stream +import kotlin.streams.asStream + +interface TextBlock { + companion object { + val TAB_REPLACEMENT: CharSequence = " " + const val DELIMITER: String = "\n" + } + + fun rawString(): Array + + val textBlock: CharSequence + get() = rawString().joinToString(DELIMITER) + + fun withIndent(indent: CharSequence): TextBlock + + fun stream(): Stream = rawString().asSequence().asStream() +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/TextBlockFactory.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/TextBlockFactory.kt new file mode 100644 index 00000000..42c633ed --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/TextBlockFactory.kt @@ -0,0 +1,12 @@ +package com.simiacryptus.aicoder.util + +interface TextBlockFactory { + fun fromString(text: String?): T + + @Suppress("unused") + fun toString(text: T): CharSequence? { + return text.toString() + } + + fun looksLike(text: String?): Boolean +} diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/UITools.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/UITools.kt new file mode 100644 index 00000000..6a7420be --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/UITools.kt @@ -0,0 +1,851 @@ +package com.simiacryptus.aicoder.util + +import aicoder.actions.agent.toFile +import com.google.common.util.concurrent.* +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.editor.Caret +import com.intellij.openapi.editor.Document +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.progress.util.AbstractProgressIndicatorBase +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.ComboBox +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.ui.components.JBLabel +import com.intellij.ui.dsl.builder.* +import com.intellij.util.ui.FormBuilder +import com.simiacryptus.aicoder.config.AppSettingsState +import com.simiacryptus.aicoder.config.Name +import com.simiacryptus.aicoder.util.BrowseUtil.browse +import com.simiacryptus.jopenai.OpenAIClient +import com.simiacryptus.jopenai.exceptions.ModerationException +import com.simiacryptus.jopenai.models.APIProvider +import org.slf4j.LoggerFactory +import java.awt.BorderLayout +import java.awt.Component +import java.awt.Dimension +import java.awt.Toolkit +import java.awt.event.ComponentAdapter +import java.awt.event.ComponentEvent +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent +import java.beans.PropertyChangeEvent +import java.io.IOException +import java.io.PrintWriter +import java.io.StringWriter +import java.net.URI +import java.util.* +import java.util.concurrent.* +import java.util.concurrent.atomic.AtomicReference +import java.util.function.Supplier +import javax.swing.* +import javax.swing.text.JTextComponent +import kotlin.math.max +import kotlin.reflect.KClass +import kotlin.reflect.KMutableProperty +import kotlin.reflect.KProperty1 +import kotlin.reflect.KVisibility +import kotlin.reflect.full.memberProperties +import kotlin.reflect.jvm.isAccessible +import kotlin.reflect.jvm.javaType + +object UITools { + val retry = WeakHashMap() + + fun showError(project: Project?, message: String, title: String = "Error") { + Messages.showErrorDialog(project, message, title) + } + + fun showWarning(project: Project?, message: String, title: String = "Warning") { + Messages.showWarningDialog(project, message, title) + } + + private val log = LoggerFactory.getLogger(UITools::class.java) + private val threadFactory: ThreadFactory = ThreadFactoryBuilder().setNameFormat("API Thread %d").build() + private val pool: ListeningExecutorService by lazy { + MoreExecutors.listeningDecorator( + ThreadPoolExecutor(/* corePoolSize = */ AppSettingsState.instance.apiThreads,/* maximumPoolSize = */ + AppSettingsState.instance.apiThreads,/* keepAliveTime = */ + 0L,/* unit = */ + TimeUnit.MILLISECONDS,/* workQueue = */ + LinkedBlockingQueue(),/* threadFactory = */ + threadFactory,/* handler = */ + ThreadPoolExecutor.AbortPolicy() + ) + ) + } + val scheduledPool: ListeningScheduledExecutorService by lazy { + MoreExecutors.listeningDecorator(ScheduledThreadPoolExecutor(1, threadFactory)) + } + private val errorLog = mutableListOf>() + private val actionLog = mutableListOf() + private val singleThreadPool = Executors.newSingleThreadExecutor() + + fun getRoot(e: AnActionEvent): String { + return getSelectedFolder(e)?.toFile?.absolutePath ?: getSelectedFile(e)?.toFile?.parent ?: "" + } + + fun redoableTask( + event: AnActionEvent, + request: Supplier, + ) { + log.debug("Starting redoableTask with event: ${event}, request: ${request}") + Futures.addCallback(pool.submit { + request.get() + }, futureCallback(event, request), pool) + log.debug("Submitted redoableTask for execution") + } + + private fun futureCallback( + event: AnActionEvent, + request: Supplier, + ) = object : FutureCallback { + override fun onSuccess(undo: Runnable) { + val requiredData = event.getData(CommonDataKeys.EDITOR) ?: return + val document = requiredData.document + retry[document] = getRetry(event, request, undo) + } + + override fun onFailure(t: Throwable) { + error(log, "Error", t) + } + } + + fun getRetry( + event: AnActionEvent, + request: Supplier, + undo: Runnable, + ): Runnable = Runnable { + Futures.addCallback( + pool.submit { + WriteCommandAction.runWriteCommandAction(event.project) { undo.run() } + request.get() + }, futureCallback(event, request), pool + ) + } + + fun replaceString(document: Document, startOffset: Int, endOffset: Int, newText: CharSequence): Runnable { + log.debug("Invoking replaceString with startOffset: $startOffset, endOffset: $endOffset, newText: $newText") + val oldText: CharSequence = document.getText(TextRange(startOffset, endOffset)) + document.replaceString(startOffset, endOffset, newText) + logEdit( + String.format( + "FWD replaceString from %s to %s (%s->%s): %s", startOffset, endOffset, endOffset - startOffset, newText.length, newText + ) + ) + return Runnable { + val verifyTxt = document.getText(TextRange(startOffset, startOffset + newText.length)) + log.debug("Verifying text after replaceString: expected: $newText, actual: $verifyTxt") + if (verifyTxt != newText) { + val msg = String.format( + "The text range from %d to %d does not match the expected text \"%s\" and is instead \"%s\"", + startOffset, + startOffset + newText.length, + newText, + verifyTxt + ) + log.error("Verification failed after replaceString: $msg") + throw IllegalStateException(msg) + } + document.replaceString(startOffset, startOffset + newText.length, oldText) + logEdit( + String.format( + "REV replaceString from %s to %s (%s->%s): %s", startOffset, startOffset + newText.length, newText.length, oldText.length, oldText + ) + ) + } + } + + fun insertString(document: Document, startOffset: Int, newText: CharSequence): Runnable { + document.insertString(startOffset, newText) + logEdit(String.format("FWD insertString @ %s (%s): %s", startOffset, newText.length, newText)) + return Runnable { + val verifyTxt = document.getText(TextRange(startOffset, startOffset + newText.length)) + if (verifyTxt != newText) { + val message = String.format( + "The text range from %d to %d does not match the expected text \"%s\" and is instead \"%s\"", + startOffset, + startOffset + newText.length, + newText, + verifyTxt + ) + throw AssertionError(message) + } + document.deleteString(startOffset, startOffset + newText.length) + logEdit(String.format("REV deleteString from %s to %s", startOffset, startOffset + newText.length)) + } + } + + private fun logEdit(message: String) { + log.debug(message) + } + + @Suppress("unused") + fun deleteString(document: Document, startOffset: Int, endOffset: Int): Runnable { + val oldText: CharSequence = document.getText(TextRange(startOffset, endOffset)) + document.deleteString(startOffset, endOffset) + return Runnable { + document.insertString(startOffset, oldText) + logEdit(String.format("REV insertString @ %s (%s): %s", startOffset, oldText.length, oldText)) + } + } + + fun getIndent(caret: Caret?): CharSequence { + if (null == caret) return "" + val document = caret.editor.document + val documentText = document.text + val lineNumber = document.getLineNumber(caret.selectionStart) + val lines = documentText.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + if (lines.isEmpty()) return "" + return IndentedText.fromString(lines[max(lineNumber, 0).coerceAtMost(lines.size - 1)]).indent + } + + @Suppress("unused") + fun hasSelection(e: AnActionEvent): Boolean { + val caret = e.getData(CommonDataKeys.CARET) + return null != caret && caret.hasSelection() + } + + fun getIndent(event: AnActionEvent): CharSequence { + val caret = event.getData(CommonDataKeys.CARET) + val indent: CharSequence = if (null == caret) { + "" + } else { + getIndent(caret) + } + return indent + } + + fun readKotlinUIViaReflection( + settings: T, + component: R, + componentClass: KClass<*> = component::class, + ) { + + val declaredUIFields = componentClass.memberProperties.map { it.name }.toSet() + for (settingsField in settings.javaClass.kotlin.memberProperties) { + if (settingsField is KMutableProperty<*>) { + settingsField.isAccessible = true + val settingsFieldName = settingsField.name + try { + var newSettingsValue: Any? = null + if (!declaredUIFields.contains(settingsFieldName)) continue + val uiField: KProperty1 = (componentClass.memberProperties.find { it.name == settingsFieldName } as KProperty1?)!! + var uiVal = uiField.get(component) + if (uiVal is JScrollPane) { + uiVal = uiVal.viewport.view + } + when (settingsField.returnType.javaType.typeName) { + "java.lang.String" -> if (uiVal is JTextComponent) { + newSettingsValue = uiVal.text + } else if (uiVal is ComboBox<*>) { + newSettingsValue = uiVal.item + } + + "int", "java.lang.Integer" -> if (uiVal is JTextComponent) { + newSettingsValue = if (uiVal.text.isBlank()) -1 else uiVal.text.toInt() + } + + "long" -> if (uiVal is JTextComponent) { + newSettingsValue = if (uiVal.text.isBlank()) -1 else uiVal.text.toLong() + } + + "double", "java.lang.Double" -> if (uiVal is JTextComponent) { + newSettingsValue = if (uiVal.text.isBlank()) 0.0 else uiVal.text.toDouble() + } + + "boolean" -> if (uiVal is JCheckBox) { + newSettingsValue = uiVal.isSelected + } else if (uiVal is JTextComponent) { + newSettingsValue = java.lang.Boolean.parseBoolean(uiVal.text) + } + + else -> if (Enum::class.java.isAssignableFrom(settingsField.returnType.javaType as Class<*>)) { + if (uiVal is ComboBox<*>) { + val comboBox = uiVal + val item = comboBox.item + val enumClass = settingsField.returnType.javaType as Class?> + val string = item.toString() + newSettingsValue = findValue(enumClass, string) + } + } + } + settingsField.setter.call(settings, newSettingsValue) + } catch (e: Throwable) { + throw RuntimeException("Error processing $settingsField", e) + } + } + } + } + + private fun findValue(enumClass: Class?>, string: String): Enum<*>? { + // First try case-insensitive match + val caseInsensitiveMatch = enumClass.enumConstants?.firstOrNull { + it?.name?.equals(string, ignoreCase = true) == true + } + if (caseInsensitiveMatch != null) return caseInsensitiveMatch + // Fall back to exact case match + return try { + java.lang.Enum.valueOf(enumClass, string) + } catch (e: IllegalArgumentException) { + null + } + } + + fun writeKotlinUIViaReflection( + settings: T, component: R, componentClass: KClass<*> + ) { + val declaredUIFields = componentClass.memberProperties.map { it.name }.toSet() + val memberProperties = settings.javaClass.kotlin.memberProperties + val publicProperties = memberProperties.filter { + it.visibility == KVisibility.PUBLIC && (it is KMutableProperty<*> || it.isAccessible) + } + for (settingsField in publicProperties) { + settingsField.isAccessible = true + val fieldName = settingsField.name + try { + if (!declaredUIFields.contains(fieldName)) { + log.warn("Field not found: $fieldName") + continue + } + val uiField = (componentClass.memberProperties.find { it.name == fieldName } + ?: throw IllegalStateException("UI field not found: $fieldName")) as KProperty1 + uiField.isAccessible = true + val settingsVal = settingsField.get(settings) ?: continue + var uiVal = uiField.get(component) + if (uiVal is JScrollPane) { + uiVal = uiVal.viewport.view + } + when (settingsField.returnType.javaType.typeName) { + "java.lang.String" -> if (uiVal is JTextComponent) { + uiVal.text = settingsVal.toString() + } else if (uiVal is ComboBox<*>) { + (uiVal as ComboBox).item = settingsVal.toString() + } + + "int", "java.lang.Integer" -> if (uiVal is JTextComponent) { + uiVal.text = (settingsVal as Int).toString() + } + + "long" -> if (uiVal is JTextComponent) { + uiVal.text = (settingsVal as Int).toLong().toString() + } + + "boolean" -> if (uiVal is JCheckBox) { + uiVal.isSelected = (settingsVal as Boolean) + } else if (uiVal is JTextComponent) { + uiVal.text = java.lang.Boolean.toString((settingsVal as Boolean)) + } + + "double", "java.lang.Double" -> if (uiVal is JTextComponent) { + uiVal.text = (settingsVal as Double).toString() + } + + else -> if (uiVal is ComboBox<*>) { + (uiVal as ComboBox).item = settingsVal.toString() + } + } + } catch (e: Throwable) { + throw RuntimeException("Error processing $settingsField", e) + } + } + } + + private fun addKotlinFields(ui: T, formBuilder: FormBuilder, fillVertically: Boolean) { + var first = true + for (field in ui.javaClass.kotlin.memberProperties.filterNotNull()) { + try { + val nameAnnotation = field.annotations.find { it is Name } as Name? + val component = field.get(ui) as JComponent + if (nameAnnotation != null) { + if (first && fillVertically) { + first = false + formBuilder.addLabeledComponentFillVertically(nameAnnotation.value + ": ", component) + } else { + formBuilder.addLabeledComponent(JBLabel(nameAnnotation.value + ": "), component, 1, false) + } + } else { + formBuilder.addComponentToRightColumn(component, 1) + } + } catch (e: IllegalAccessException) { + throw RuntimeException(e) + } catch (e: Throwable) { + error(log, "Error processing " + field.name, e) + } + } + } + + private fun getMaximumSize(factor: Double): Dimension { + val screenSize = Toolkit.getDefaultToolkit().screenSize + return Dimension((screenSize.getWidth() * factor).toInt(), (screenSize.getHeight() * factor).toInt()) + } + + private fun showOptionDialog(mainPanel: JPanel?, vararg options: Any, title: String, modal: Boolean = true): Int { + val pane = getOptionPane(mainPanel, options) + val rootFrame = JOptionPane.getRootFrame() + pane.componentOrientation = rootFrame.componentOrientation + val dialog = JDialog(rootFrame, title, modal) + dialog.componentOrientation = rootFrame.componentOrientation + + val latch = if (!modal) CountDownLatch(1) else null + configure(dialog, pane, latch) + dialog.isVisible = true + if (!modal) latch?.await() + + dialog.dispose() + return getSelectedValue(pane, options) + } + + private fun getOptionPane( + mainPanel: JPanel?, + options: Array, + ): JOptionPane { + val pane = JOptionPane( + mainPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.NO_OPTION, null, options, options[0] + ) + pane.initialValue = options[0] + return pane + } + + private fun configure(dialog: JDialog, pane: JOptionPane, latch: CountDownLatch? = null) { + val contentPane = dialog.contentPane + contentPane.layout = BorderLayout() + contentPane.add(pane, BorderLayout.CENTER) + + if (JDialog.isDefaultLookAndFeelDecorated() && UIManager.getLookAndFeel().supportsWindowDecorations) { + dialog.isUndecorated = true + pane.rootPane.windowDecorationStyle = JRootPane.PLAIN_DIALOG + } + dialog.isResizable = true + dialog.maximumSize = getMaximumSize(0.9) + dialog.pack() + dialog.setLocationRelativeTo(null as Component?) + val adapter: WindowAdapter = windowAdapter(pane, dialog) + dialog.addWindowListener(adapter) + dialog.addWindowFocusListener(adapter) + dialog.addComponentListener(object : ComponentAdapter() { + override fun componentShown(ce: ComponentEvent) { + // reset value to ensure closing works properly + pane.value = JOptionPane.UNINITIALIZED_VALUE + } + }) + pane.addPropertyChangeListener { event: PropertyChangeEvent -> + if (dialog.isVisible && event.source === pane && event.propertyName == JOptionPane.VALUE_PROPERTY && event.newValue != null && event.newValue !== JOptionPane.UNINITIALIZED_VALUE) { + dialog.isVisible = false + latch?.countDown() + } + } + + pane.selectInitialValue() + } + + private fun windowAdapter(pane: JOptionPane, dialog: JDialog): WindowAdapter { + val adapter: WindowAdapter = object : WindowAdapter() { + private var gotFocus = false + override fun windowClosing(we: WindowEvent) { + pane.value = null + } + + override fun windowClosed(e: WindowEvent) { + pane.removePropertyChangeListener { event: PropertyChangeEvent -> + if (dialog.isVisible && event.source === pane && event.propertyName == JOptionPane.VALUE_PROPERTY && event.newValue != null && event.newValue !== JOptionPane.UNINITIALIZED_VALUE) { + dialog.isVisible = false + } + } + dialog.contentPane.removeAll() + } + + override fun windowGainedFocus(we: WindowEvent) { + if (!gotFocus) { + pane.selectInitialValue() + gotFocus = true + } + } + } + return adapter + } + + private fun getSelectedValue(pane: JOptionPane, options: Array): Int { + val selectedValue = pane.value ?: return JOptionPane.CLOSED_OPTION + var counter = 0 + val maxCounter = options.size + while (counter < maxCounter) { + if (options[counter] == selectedValue) return counter + counter++ + } + return JOptionPane.CLOSED_OPTION + } + + fun showCheckboxDialog( + promptMessage: String, + checkboxIds: Array, + checkboxDescriptions: Array, + ): Array { + val checkboxMap = HashMap() + val panel = panel { + for (i in checkboxIds.indices) { + row { + val checkbox = checkBox(checkboxDescriptions[i]).selected(true).component + checkboxMap[checkboxIds[i]] = checkbox + } + } + } + val dialogResult = showOptionDialog(panel, "OK", title = promptMessage) + val selectedIds = ArrayList() + if (dialogResult == 0) { + for ((checkboxId, checkbox) in checkboxMap) { + if (checkbox.isSelected) { + selectedIds.add(checkboxId) + } + } + } + return selectedIds.toTypedArray() + } + + fun showRadioButtonDialog( + promptMessage: CharSequence, + vararg radioButtonDescriptions: CharSequence, + ): CharSequence? { + val radioButtonMap = HashMap() + val buttonGroup = ButtonGroup() + val panel = panel { + for (description in radioButtonDescriptions) { + row { + val radioButton = radioButton(description.toString()).selected(true).component + radioButtonMap[description.toString()] = radioButton + buttonGroup.add(radioButton) + } + } + } + val dialogResult = showOptionDialog(panel, "OK", title = promptMessage.toString()) + if (dialogResult == 0) { + for ((radioButtonId, radioButton) in radioButtonMap) { + if (radioButton.isSelected) { + return radioButtonId + } + } + } + return null + } + + fun buildFormViaReflection( + component: T, + fillVertically: Boolean = true, + formBuilder: FormBuilder = FormBuilder.createFormBuilder(), + ): JPanel? { + addKotlinFields(component, formBuilder, fillVertically) + return formBuilder.addComponentFillVertically(JPanel(), 0).panel + } + + fun showDialog( + project: Project?, + uiClass: Class, + configClass: Class, + title: String = "Generate Project", + onComplete: (C) -> Unit = { _ -> }, + ): C = showDialog( + project, uiClass.getConstructor().newInstance(), configClass.getConstructor().newInstance(), title, onComplete + ) + + fun showDialog( + project: Project?, component: T, config: C, title: String, onComplete: (C) -> Unit + ): C { + log.debug("Showing dialog with title: $title") + val dialog = object : DialogWrapper(project) { + init { + this.init() + this.title = title + this.setOKButtonText("Generate") + this.setCancelButtonText("Cancel") + this.isResizable = true + } + + override fun createCenterPanel(): JComponent? { + log.debug("Creating center panel for dialog") + return buildFormViaReflection(component) + } + } + dialog.show() + log.debug("Dialog shown with result: ${dialog.isOK}") + if (dialog.isOK) { + readKotlinUIViaReflection( + settings = config, component = component, componentClass = component::class + ) + log.debug("Reading UI via reflection completed") + onComplete(config) + log.debug("onComplete callback executed") + } + return config + } + + fun getSelectedFolder(e: AnActionEvent): VirtualFile? { + val dataContext = e.dataContext + val data = PlatformDataKeys.VIRTUAL_FILE.getData(dataContext) + if (data != null && data.isDirectory) { + return data + } + val editor = PlatformDataKeys.EDITOR.getData(dataContext) + if (editor != null) { + val file = FileDocumentManager.getInstance().getFile(editor.document) + if (file != null) { + return file.parent + } + } + return null + } + + fun getSelectedFile(e: AnActionEvent): VirtualFile? { + val dataContext = e.dataContext + val data = PlatformDataKeys.VIRTUAL_FILE.getData(dataContext) + if (data != null && !data.isDirectory) { + return data + } + return null + } + + fun getSelectedFiles(e: AnActionEvent): List { + val dataContext = e.dataContext + val data = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext) + if (null != data) return data.toList() + val editor = PlatformDataKeys.EDITOR.getData(dataContext) + if (editor != null) { + val file = FileDocumentManager.getInstance().getFile(editor.document) + if (file != null) { + return listOf(file) + } + } + return emptyList() + } + + fun writeableFn( + event: AnActionEvent, + fn: () -> Runnable, + ): Runnable { + val runnable = AtomicReference() + WriteCommandAction.runWriteCommandAction(event.project) { runnable.set(fn()) } + return runnable.get() + } + + fun run( + project: Project?, + title: String?, + canBeCancelled: Boolean = true, + suppressProgress: Boolean = true, + task: (ProgressIndicator) -> T, + ): T { + return if (project == null || suppressProgress == AppSettingsState.instance.editRequests) { + AppSettingsState.instance.apiKey?.values?.firstOrNull() ?: "" + task(AbstractProgressIndicatorBase()) + } else { + AppSettingsState.instance.apiKey?.values?.firstOrNull() ?: "" + val t = if (AppSettingsState.instance.modalTasks) ModalTask(project, title ?: "", canBeCancelled, task) + else BgTask(project, title ?: "", canBeCancelled, task) + ProgressManager.getInstance().run(t) + t.get() + } + } + + + fun runAsync( + project: Project?, + title: String?, + canBeCancelled: Boolean = true, + suppressProgress: Boolean = true, + task: (ProgressIndicator) -> Unit, + ) { + Thread { + try { + if (project == null || suppressProgress == AppSettingsState.instance.editRequests) { + AppSettingsState.instance.apiKey?.values?.firstOrNull() ?: "" + task(AbstractProgressIndicatorBase()) + } else { + AppSettingsState.instance.apiKey?.values?.firstOrNull() ?: "" + val t = if (AppSettingsState.instance.modalTasks) ModalTask(project, title ?: "", canBeCancelled, task) + else BgTask(project, title ?: "", canBeCancelled, task) + ProgressManager.getInstance().run(t) + t.get() + } + } catch (e: Throwable) { + error(log, "Error running task", e) + showError(project, "Failed to initialize chat: ${e.message}") + } + }.apply { + name = title + }.start() + } + + + fun map( + moderateAsync: ListenableFuture, + o: com.google.common.base.Function, + ): ListenableFuture = Futures.transform(moderateAsync, o::apply, pool) + + + fun logAction(message: String) { + actionLog += message + } + + + fun error(log: org.slf4j.Logger, msg: String, e: Throwable) { + log.error(msg, e) + errorLog += Pair(msg, e) + singleThreadPool.submit { + if (AppSettingsState.instance.suppressErrors) { + return@submit + } else if (e.matches { ModerationException::class.java.isAssignableFrom(it.javaClass) }) { + JOptionPane.showMessageDialog( + null, e.message, "This request was rejected by OpenAI Moderation", JOptionPane.WARNING_MESSAGE + ) + } else if (e.matches { + java.lang.InterruptedException::class.java.isAssignableFrom(it.javaClass) && it.message?.contains( + "sleep interrupted" + ) == true + }) { + JOptionPane.showMessageDialog( + null, "This request was cancelled by the user", "User Cancelled Request", JOptionPane.WARNING_MESSAGE + ) + } else if (e.matches { IOException::class.java.isAssignableFrom(it.javaClass) && it.message?.contains("Incorrect API key") == true }) { + + + val panel = panel { + row { + label("The API key was rejected by the server.") + } + row { + val apiKeyInput = passwordField().columns(80).focused().component + button("Test Key") { + val apiKey = apiKeyInput.password.joinToString("") + try { + OpenAIClient( + key = mapOf( + APIProvider.OpenAI to apiKey + ) + ).listModels() + JOptionPane.showMessageDialog( + null, "The API key was accepted by the server. The new value will be saved.", "Success", JOptionPane.INFORMATION_MESSAGE + ) + AppSettingsState.instance.apiKey = mapOf(APIProvider.OpenAI.name to apiKey).toMutableMap() + } catch (e: Exception) { + JOptionPane.showMessageDialog( + null, "The API key was rejected by the server.", "Failure", JOptionPane.WARNING_MESSAGE + ) + } + } + } + row { + button("Open Account Page") { + browse(URI("https://platform.openai.com/account/api-keys")) + } + } + } + val showOptionDialog = showOptionDialog( + panel, "Dismiss", title = "Error", modal = true + ) + log.info("showOptionDialog = $showOptionDialog") + } else { + val panel = panel { + row { + label("Oops! Something went wrong. An error report has been generated. You can copy and paste the report below into a new issue on our Github page.") + } + row { + textArea().rows(40).columns(80).text( + """ + Log Message: ${msg.trimIndent()} + Error Message: ${e.message?.trimIndent()} + Error Type: ${e.javaClass.name} + API Base: ${AppSettingsState.instance.apiBase} + + OS: ${System.getProperty("os.name")} / ${System.getProperty("os.version")} / ${System.getProperty("os.arch")} + Locale: ${Locale.getDefault().country} / ${Locale.getDefault().language} + Error Details: + ``` + ${toString(e)} + ``` + Action History: + ${actionLog.joinToString("\n") { "* ${it.replace("\n", "\n ")}" }} + Error History: + ${errorLog.filter { it.second != e }.joinToString("\n") { "${it.first}\n```\n${toString(it.second)}\n```" }} + """.trimIndent() + ) + } + row { + button("Open New Issue on our Github page") { + browse(URI("https://github.com/SimiaCryptus/intellij-aicoder/issues/new")) + } + } + row { + val suppressCheckbox = checkBox("Suppress Future Error Popups").component + button("Dismiss") { + if (suppressCheckbox.isSelected) { + AppSettingsState.instance.suppressErrors = true + } + } + } + } + + val showOptionDialog = showOptionDialog( + panel, "Dismiss", title = "Error", modal = true + ) + log.info("showOptionDialog = $showOptionDialog") + } + } + } + + private fun Throwable.matches(matchFn: (Throwable) -> Boolean): Boolean { + if (matchFn(this)) return true + if (this.cause != null && this.cause !== this) return this.cause!!.matches(matchFn) + return false + } + + fun Throwable.get(matchFn: (Throwable) -> Boolean): Throwable? { + if (matchFn(this)) return this + if (this.cause != null && this.cause !== this) return this.cause!!.get(matchFn) + return null + } + + fun toString(e: Throwable): String { + val sw = StringWriter() + val pw = PrintWriter(sw) + e.printStackTrace(pw) + return sw.toString() + } + + fun showInputDialog( + parentComponent: Component?, message: Any?, title: String?, messageType: Int + ): Any? { + val icon = null + val selectionValues = null + val initialSelectionValue = null + val pane = JOptionPane(message, messageType, JOptionPane.OK_CANCEL_OPTION, icon, null, null) + pane.wantsInput = true + pane.selectionValues = selectionValues + pane.initialSelectionValue = initialSelectionValue + val dialog = pane.createDialog(parentComponent, title) + pane.selectInitialValue() + dialog.isVisible = true + dialog.dispose() + val value = pane.inputValue + return if (value == JOptionPane.UNINITIALIZED_VALUE) null else value + } + + fun showErrorDialog(errorMessage: String, title: String) { + val panel = panel { + row { label(errorMessage) } + } + showOptionDialog(panel, "OK", title = title, modal = true) + } + + fun showInfoMessage(message: String, title: String) { + val panel = panel { + row { label(message) } + } + showOptionDialog(panel, "OK", title = title, modal = true) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/psi/PsiClassContext.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/psi/PsiClassContext.kt new file mode 100644 index 00000000..a071b500 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/psi/PsiClassContext.kt @@ -0,0 +1,151 @@ +package com.simiacryptus.aicoder.util.psi + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiFile +import com.simiacryptus.aicoder.util.ComputerLanguage + +class PsiClassContext( + val text: String, + private val isPrior: Boolean, + private val isOverlap: Boolean, + val language: ComputerLanguage +) { + val children = ArrayList() + + /** + * This java code is initializing a PsiClassContext object. It is doing this by creating a PsiElementVisitor and using it to traverse the PsiFile. + * It is checking the text range of each element and whether it is prior to, overlapping, or within the selectionStart and selectionEnd parameters. + * Depending on the element, it is adding the text of the element to the PsiClassContext object, or recursively visiting its children. + * + * @param psiFile + * @param selectionStart + * @param selectionEnd + * @return + */ + fun init(psiFile: PsiFile?, selectionStart: Int, selectionEnd: Int): PsiClassContext { + object : PsiVisitorBase() { + var currentContext = this@PsiClassContext + var indent = "" + override fun visit(element: PsiElement, self: PsiElementVisitor) { + val text = element.text + val textRange = element.textRange + val textRangeEndOffset = textRange.endOffset + 1 + val textRangeStartOffset = textRange.startOffset + // Check if the element comes before the selection + val isPrior = textRangeEndOffset < selectionStart + // Check if the element overlaps with the selection + val isOverlap = + textRangeStartOffset in selectionStart..selectionEnd || textRangeEndOffset in selectionStart..selectionEnd || selectionStart in textRangeStartOffset..textRangeEndOffset || selectionEnd in textRangeStartOffset..textRangeEndOffset + // Check if the element is within the selection + val within = + selectionStart in textRangeStartOffset until textRangeEndOffset && textRangeStartOffset <= selectionEnd && textRangeEndOffset > selectionEnd + if (PsiUtil.matchesType(element, "ImportList")) { + currentContext.children.add(PsiClassContext(text.trim { it <= ' ' }, isPrior, isOverlap, language)) + } else if (PsiUtil.matchesType(element, "Comment", "DocComment")) { + if (within) { + currentContext.children.add( + PsiClassContext( + indent + text.trim { it <= ' ' }, + false, + true, + language + ) + ) + } + } else if (PsiUtil.matchesType(element, "Field")) { + processChildren( + element, + self, + isPrior, + isOverlap, + indent + PsiUtil.getDeclaration(element).trim { it <= ' ' } + if (isOverlap) " {" else ";") + } else if (PsiUtil.matchesType(element, "Method", "Function", "FunctionDefinition", "Constructor")) { + val methodTerminator = when (language) { + ComputerLanguage.Java -> " { /* ... */}" + ComputerLanguage.Kotlin -> " { /* ... */}" + ComputerLanguage.Scala -> " { /* ... */}" + else -> ";" + } + processChildren( + element, + self, + isPrior, + isOverlap, + indent + PsiUtil.getDeclaration(element) + .trim { it <= ' ' } + (if (isOverlap) " {" else methodTerminator)) + } else if (PsiUtil.matchesType(element, "LocalVariable")) { + currentContext.children.add(PsiClassContext(indent + text.trim { it <= ' ' } + ";", + isPrior, + isOverlap, + language)) + } else if (PsiUtil.matchesType(element, "Class")) { + processChildren( + element, + self, + isPrior, + isOverlap, + indent + text.substring(0, text.indexOf('{')).trim { it <= ' ' } + " {") + if (!isOverlap) { + currentContext.children.add(PsiClassContext("}", isPrior, false, language)) + } + } else if (!isOverlap && PsiUtil.matchesType(element, "CodeBlock", "ForStatement")) { + // Skip + } else { + element.acceptChildren(self) + } + } + + private fun processChildren( + element: PsiElement, + self: PsiElementVisitor, + isPrior: Boolean, + isOverlap: Boolean, + declarationText: String + ): PsiClassContext { + val newNode = PsiClassContext(declarationText, isPrior, isOverlap, language) + currentContext.children.add(newNode) + val prevclassBuffer = currentContext + currentContext = newNode + val prevIndent = indent + indent += " " + element.acceptChildren(self) + indent = prevIndent + currentContext = prevclassBuffer + return newNode + } + }.build(psiFile!!) + return this + } + + override fun toString(): String { + val sb = ArrayList() + sb.add(text) + children.stream().filter { x: PsiClassContext -> x.isPrior }.map { obj: PsiClassContext -> obj.toString() } + .forEach { e: String -> sb.add(e) } + children.stream().filter { x: PsiClassContext -> !x.isOverlap && !x.isPrior } + .map { obj: PsiClassContext -> obj.toString() } + .forEach { e: String -> sb.add(e) } + children.stream().filter { x: PsiClassContext -> x.isOverlap }.map { obj: PsiClassContext -> obj.toString() } + .forEach { e: String -> sb.add(e) } + return sb.stream().reduce { l: String, r: String -> + """ + $l + $r + """.trimIndent() + }.get() + } + + companion object { + @JvmStatic + fun getContext( + psiFile: PsiFile?, + selectionStart: Int, + selectionEnd: Int, + language: ComputerLanguage + ): PsiClassContext { + return PsiClassContext("", false, true, language).init(psiFile, selectionStart, selectionEnd) + } + + } +} diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/psi/PsiUtil.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/psi/PsiUtil.kt new file mode 100644 index 00000000..6a646383 --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/psi/PsiUtil.kt @@ -0,0 +1,260 @@ +package com.simiacryptus.aicoder.util.psi + +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementVisitor +import com.simiacryptus.util.StringUtil +import java.util.* +import java.util.concurrent.atomic.AtomicReference +import java.util.stream.Collectors +import java.util.stream.Stream + +object PsiUtil { + val ELEMENTS_CODE = arrayOf( + "Method", "Field", "Class", "Function", "CssBlock", "FunctionDefinition", + "Property", "Interface", "Enum", "Constructor", "Parameter", "Variable" + ) + val ELEMENTS_COMMENTS = arrayOf( + "Comment", "DocComment", "LineComment", "BlockComment", "JavadocComment" + ) + + // Common block types used in multiple places + private val BLOCK_TYPES = arrayOf( + "CodeBlock", "BlockExpr", "Block", "BlockExpression", "StatementList", "BlockFields", + "ClassBody", "MethodBody", "FunctionBody", "TryBlock", "CatchBlock", "FinallyBlock" + ) + + /** + * Gets the name of an element (class, method, field etc) + */ + fun getName(element: PsiElement): String? { + if (!matchesType(element, *ELEMENTS_CODE)) return null + val declaration = getDeclaration(element) + // Extract name from declaration based on element type + return when { + matchesType(element, "Class", "Interface", "Enum") -> + declaration.substringAfter("class ") + .substringAfter("interface ") + .substringAfter("enum ") + .substringBefore("<") + .substringBefore(" ") + .trim() + + matchesType(element, "Method", "Function") -> + declaration.substringAfter(" ") + .substringBefore("(") + .trim() + + matchesType(element, "Field", "Variable") -> + declaration.substringAfterLast(" ") + .substringBefore("=") + .trim() + + else -> null + } + } + + fun getAll(element: PsiElement, vararg types: CharSequence): List { + val elements: MutableList = ArrayList() + val visitor = AtomicReference() + visitor.set(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + if (matchesType(element, *types)) { + elements.add(element) + } + element.acceptChildren(visitor.get()) + super.visitElement(element) + } + }) + element.accept(visitor.get()) + return elements + } + + fun getSmallestIntersecting( + element: PsiElement, selectionStart: Int, selectionEnd: Int, vararg types: CharSequence + ): PsiElement? { + val smallest = AtomicReference(null) + val visitor = AtomicReference() + visitor.set(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + val textRange = element.textRange + if (intersects(TextRange(selectionStart, selectionEnd), textRange)) { + if (matchesType(element, *types)) { + smallest.updateAndGet { s: PsiElement? -> + if ((s?.text?.length ?: Int.MAX_VALUE) < element.text.length) s else element + } + } + } + super.visitElement(element) + element.acceptChildren(visitor.get()) + } + }) + element.accept(visitor.get()) + return smallest.get() + } + + private fun within(textRange: TextRange, vararg offset: Int): Boolean = offset.any { it in textRange.startOffset..textRange.endOffset } + private fun intersects(a: TextRange, b: TextRange): Boolean { + return within(a, b.startOffset, b.endOffset) || within(b, a.startOffset, a.endOffset) + } + + fun matchesType(element: PsiElement, vararg types: CharSequence): Boolean { + return matchesType(element.javaClass.simpleName, types) + } + + fun matchesType(simpleName: CharSequence, types: Array): Boolean { + var simpleName1 = simpleName + simpleName1 = StringUtil.stripSuffix(simpleName1, "Impl") + simpleName1 = StringUtil.stripPrefix(simpleName1, "Psi") + val str = simpleName1.toString() + return Stream.of(*types).map { s: CharSequence? -> + StringUtil.stripSuffix( + s!!, "Impl" + ) + }.map { s: String? -> + StringUtil.stripPrefix( + s!!, "Psi" + ) + }.anyMatch { t: CharSequence -> str.endsWith(t.toString()) } + } + + fun getFirstBlock(element: PsiElement, vararg blockType: CharSequence): PsiElement? { + val children = element.children + if (children.isEmpty()) return null + val first = children[0] + return if (matchesType(first, *blockType)) first else null + } + + fun getLargestBlock(element: PsiElement, vararg blockType: CharSequence): PsiElement? { + val largest = AtomicReference(null) + val visitor = AtomicReference() + visitor.set(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + if (matchesType(element, *blockType)) { + largest.updateAndGet { s: PsiElement? -> if (s != null && s.text.length > element.text.length) s else element } + super.visitElement(element) + } else { + super.visitElement(element) + } + element.acceptChildren(visitor.get()) + } + }) + element.accept(visitor.get()) + return largest.get() + } + + fun printTree(element: PsiElement): String { + val builder = StringBuilder() + printTree(element, builder, 0) + return builder.toString() + } + + private fun printTree(element: PsiElement, builder: StringBuilder, level: Int) { + builder.append(" ".repeat(0.coerceAtLeast(level))) + val elementClass: Class = element.javaClass + val simpleName = getName(elementClass) + builder.append(simpleName).append(" ").append(element.text.replace("\n".toRegex(), "\\\\n")) + builder.append("\n") + for (child in element.children) { + printTree(child, builder, level + 1) + } + } + + private fun getName(elementClass: Class<*>): String { + var elementClassVar = elementClass + val stringBuilder = StringBuilder() + val interfaces = getInterfaces(elementClassVar) + while (elementClassVar != Any::class.java) { + if (stringBuilder.isNotEmpty()) stringBuilder.append("/") + stringBuilder.append(elementClassVar.simpleName) + elementClassVar = elementClassVar.superclass + } + stringBuilder.append("[ ") + stringBuilder.append(interfaces.stream().sorted().collect(Collectors.joining(","))) + stringBuilder.append("]") + return stringBuilder.toString() + } + + fun getInterfaces(elementClass: Class<*>): Set { + val strings = Arrays.stream(elementClass.interfaces).map { obj: Class<*> -> obj.simpleName }.collect( + Collectors.toCollection { HashSet() }) + if (elementClass.superclass != Any::class.java) strings.addAll(getInterfaces(elementClass.superclass)) + return strings + } + + fun getLargestContainedEntity(element: PsiElement?, selectionStart: Int, selectionEnd: Int): PsiElement? { + if (null == element) return null + val textRange = element.textRange + if (textRange.startOffset >= selectionStart && textRange.endOffset <= selectionEnd) return element + var largestContainedChild: PsiElement? = null + for (child in element.children) { + val entity = getLargestContainedEntity(child, selectionStart, selectionEnd) + if (null != entity) { + if (largestContainedChild == null || largestContainedChild.textRange.length < entity.textRange.length) { + largestContainedChild = entity + } + } + } + return largestContainedChild + } + + fun getLargestContainedEntity(e: AnActionEvent): PsiElement? { + val caret = e.getData(CommonDataKeys.CARET) ?: return null + var psiFile: PsiElement? = e.getData(CommonDataKeys.PSI_FILE) ?: return null + val selectionStart = caret.selectionStart + val selectionEnd = caret.selectionEnd + val largestContainedEntity = getLargestContainedEntity(psiFile, selectionStart, selectionEnd) + if (largestContainedEntity != null) psiFile = largestContainedEntity + return psiFile + } + + fun getSmallestContainingEntity(element: PsiElement?, selectionStart: Int, selectionEnd: Int, minSize: Int = 0): PsiElement? { + if (null == element) { + return null + } + for (child in element.children) { + val entity = getSmallestContainingEntity(child, selectionStart, selectionEnd, minSize) + if (null != entity) { + return entity + } + } + val textRange = element.textRange + if (textRange.startOffset <= selectionStart) { + if (textRange.endOffset >= selectionEnd) { + if (element.text.length >= minSize) { + return element + } + } + } + return null + } + + fun getCodeElement( + psiFile: PsiElement?, selectionStart: Int, selectionEnd: Int + ) = getSmallestIntersecting(psiFile!!, selectionStart.toInt(), selectionEnd.toInt(), *ELEMENTS_CODE) + + fun getDeclaration(element: PsiElement): String { + var declaration: CharSequence = element.text + declaration = StringUtil.stripPrefix(declaration.toString().trim { it <= ' ' }, getDocComment(element).trim { it <= ' ' }) + declaration = StringUtil.stripSuffix(declaration.toString().trim { it <= ' ' }, getCode(element).trim { it <= ' ' }) + return declaration.toString().trim { it <= ' ' } + } + + fun getCode(element: PsiElement): String { + val codeBlock = getLargestBlock(element, *BLOCK_TYPES) + var code = "" + if (null != codeBlock) { + code = codeBlock.text + } + return code + } + + fun getDocComment(element: PsiElement): String { + var docComment = getLargestBlock(element, *ELEMENTS_COMMENTS) + if (null == docComment) docComment = getFirstBlock(element, *ELEMENTS_COMMENTS) + return docComment?.text?.trim() ?: "" + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/simiacryptus/aicoder/util/psi/PsiVisitorBase.kt b/src/main/kotlin/com/simiacryptus/aicoder/util/psi/PsiVisitorBase.kt new file mode 100644 index 00000000..75f0a55a --- /dev/null +++ b/src/main/kotlin/com/simiacryptus/aicoder/util/psi/PsiVisitorBase.kt @@ -0,0 +1,21 @@ +package com.simiacryptus.aicoder.util.psi + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiFile +import java.util.concurrent.atomic.AtomicReference + +abstract class PsiVisitorBase { + fun build(psiFile: PsiFile) { + val visitor = AtomicReference() + visitor.set(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + visit(element, visitor.get()) + super.visitElement(element) + } + }) + psiFile.accept(visitor.get()) + } + + protected abstract fun visit(element: PsiElement, self: PsiElementVisitor) +} diff --git a/src/main/kotlin/icons/MyIcons.kt b/src/main/kotlin/icons/MyIcons.kt index 18155d18..62998eda 100644 --- a/src/main/kotlin/icons/MyIcons.kt +++ b/src/main/kotlin/icons/MyIcons.kt @@ -4,12 +4,12 @@ import com.intellij.openapi.util.IconLoader object MyIcons { - @JvmField - val icon = IconLoader.getIcon("/META-INF/toolbarIcon.svg", javaClass) - /* - IconLoader.findIcon( - url = classLoader.getResource("./META-INF/toolbarIcon.svg"), - storeToCache = true - ) - */ + @JvmField + val icon = IconLoader.getIcon("/META-INF/toolbarIcon.svg", javaClass) + /* + IconLoader.findIcon( + url = classLoader.getResource("./META-INF/toolbarIcon.svg"), + storeToCache = true + ) + */ } \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 0ead07bf..37bffe18 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -5,291 +5,348 @@ Code Tools com.intellij.modules.platform com.intellij.modules.lang + org.jetbrains.plugins.yaml + com.intellij.modules.java - - + + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + - - diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties new file mode 100644 index 00000000..ee5864bd --- /dev/null +++ b/src/main/resources/messages.properties @@ -0,0 +1,22 @@ +# General widget messages +widget.description=AI Coding Assistant settings and controls +# Tree components +tree.accessible.name={0} Selection Tree +tree.accessible.description=Tree for selecting AI models. Use arrow keys to navigate. +# Temperature slider +slider.temperature.name=Temperature Control +slider.temperature.description=Adjust AI response creativity from 0 (focused) to 1 (creative) +label.temperature.description=Current temperature value +# Server controls +button.server.start=Start Server +button.server.stop=Stop Server +button.server.start.description=Start the AI Coding Assistant server +button.server.stop.description=Stop the AI Coding Assistant server +# Session labels +session.label.format={0} ({1}) +session.unknown=Unknown Session +# Server status +server.status.running=Server running on {0}:{1} +server.status.stopped=Server stopped +# Tooltip format +tooltip.format=Smart Model: {0}\nFast Model: {1}\nTemperature: {2}\n{3} \ No newline at end of file diff --git a/src/main/resources/messages/SettingsWidget.properties b/src/main/resources/messages/SettingsWidget.properties new file mode 100644 index 00000000..7e026599 --- /dev/null +++ b/src/main/resources/messages/SettingsWidget.properties @@ -0,0 +1,23 @@ +# Tree components +tree.description=%s selection tree for AI models +tree.selected=Selected model: %s +# Temperature slider +slider.description=Temperature control for AI model responses +slider.value=Temperature set to %.2f +label.temperature=Current temperature value +# Server controls +panel.server.description=Server control panel for AI Coding Assistant +button.server.start=Start Server +button.server.stop=Stop Server +button.server.start.description=Start the AI Coding Assistant server +button.server.stop.description=Stop the AI Coding Assistant server +# Sessions list +list.sessions.name=Active Sessions +list.sessions.description=List of currently active AI coding sessions +session.item.description=Session: %s +# Popup dialog +popup.description=AI Coding Assistant settings dialog +tabs.description=Settings categories for AI Coding Assistant +# General messages +settings.title=AI Coding Assistant Settings +settings.tooltip=Configure AI Coding Assistant settings \ No newline at end of file diff --git a/src/main/resources/messages/SettingsWidget_ar.properties b/src/main/resources/messages/SettingsWidget_ar.properties new file mode 100644 index 00000000..7065269a --- /dev/null +++ b/src/main/resources/messages/SettingsWidget_ar.properties @@ -0,0 +1,17 @@ +tree.description=شجرة اختيار %s لنماذج الذكاء الاصطناعي +tree.selected=النموذج المحدد: %s +slider.description=التحكم في درجة حرارة استجابات نموذج الذكاء الاصطناعي +slider.value=تم ضبط درجة الحرارة على %.2f +label.temperature=قيمة درجة الحرارة الحالية +panel.server.description=لوحة التحكم بالخادم لمساعد البرمجة بالذكاء الاصطناعي +button.server.start=تشغيل الخادم +button.server.stop=إيقاف الخادم +button.server.start.description=بدء تشغيل خادم مساعد البرمجة بالذكاء الاصطناعي +button.server.stop.description=إيقاف خادم مساعد البرمجة بالذكاء الاصطناعي +list.sessions.name=الجلسات النشطة +list.sessions.description=قائمة جلسات البرمجة النشطة حالياً +session.item.description=الجلسة: %s +popup.description=مربع حوار إعدادات مساعد البرمجة بالذكاء الاصطناعي +tabs.description=فئات الإعدادات لمساعد البرمجة بالذكاء الاصطناعي +settings.title=إعدادات مساعد البرمجة بالذكاء الاصطناعي +settings.tooltip=تكوين إعدادات مساعد البرمجة بالذكاء الاصطناعي \ No newline at end of file diff --git a/src/main/resources/messages/TokenCountWidget.properties b/src/main/resources/messages/TokenCountWidget.properties new file mode 100644 index 00000000..79a51166 --- /dev/null +++ b/src/main/resources/messages/TokenCountWidget.properties @@ -0,0 +1,23 @@ +### Widget general +widget.description=Token counter for code and text content +widget.display_name=Token Counter +### Tooltips +tooltip.default=Current file token count +tooltip.no_file=No file selected +tooltip.file_info=File: %s
Tokens: %d +### Status messages +status.calculating=Calculating%s +### Token count formats +count.zero=0 Tokens +count.one=1 Token +count.chars=%d Chars +count.millions=%dM Tokens +count.thousands=%dK Tokens +count.normal=%d Tokens +### Processing tooltip +tooltip.calculating_html=\ +
\ +
%s Processing
\ +
Calculating token count for selected content
\ +
Please wait while processing...
\ +
\ No newline at end of file diff --git a/src/main/resources/messages/TokenCountWidget_ar.properties b/src/main/resources/messages/TokenCountWidget_ar.properties new file mode 100644 index 00000000..c0b6bdcc --- /dev/null +++ b/src/main/resources/messages/TokenCountWidget_ar.properties @@ -0,0 +1,18 @@ +widget.description=عداد الرموز للكود والنصوص +widget.display_name=عداد الرموز +tooltip.default=عدد الرموز للملف الحالي +tooltip.no_file=لم يتم تحديد ملف +tooltip.file_info=الملف: %s
الرموز: %d +status.calculating=جارٍ الحساب%s +count.zero=٠ رمز +count.one=رمز واحد +count.chars=%d حرف +count.millions=%d مليون رمز +count.thousands=%d ألف رمز +count.normal=%d رمز +tooltip.calculating_html=\ +
\ +
%s جارٍ المعالجة
\ +
حساب عدد الرموز للمحتوى المحدد
\ +
يرجى الانتظار أثناء المعالجة...
\ +
\ No newline at end of file diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/ApplicationDevelopmentUITest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/ApplicationDevelopmentUITest.kt deleted file mode 100644 index 2b80891a..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/ApplicationDevelopmentUITest.kt +++ /dev/null @@ -1,310 +0,0 @@ -package com.github.simiacryptus.aicoder.test - -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.awaitBackgroundProgress -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.canRunTests -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.click -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.enterLines -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.getEditor -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.keyboard -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.menuAction -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.newFile -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.outputDir -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.screenshot -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.selectText -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.testProjectPath -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.writeImage -import org.apache.commons.io.FileUtils -import org.junit.jupiter.api.Test -import java.awt.event.KeyEvent -import java.io.File -import java.io.FileOutputStream -import java.io.PrintWriter -import java.lang.Thread.sleep - -/** - * See Also: - * https://github.com/JetBrains/intellij-ui-test-robot - * https://joel-costigliola.github.io/assertj/swing/api/org/assertj/swing/core/Robot.html - */ -class ApplicationDevelopmentUITest { - - @Test - fun java_test() { - if (!canRunTests()) return - val (name, description) = test_problem_calculator() - val (language, functionalHandle, seedPrompt) = java(name) - test(name, language, description, seedPrompt, functionalHandle) - } - - private fun java(name: String) = - Triple("java", "static void main", """public class $name {\n""") - - @Test - fun kotlin_test() { - if (!canRunTests()) return - val (name, description) = test_problem_calculator() - val (language, functionalHandle, seedPrompt) = kotlin(name) - test(name, language, description, seedPrompt, functionalHandle) - } - - private fun kotlin(name: String) = - Triple("kt", "fun main", """object $name {\n""") - - @Test - fun scala_test() { - if (!canRunTests()) return - val (name, description) = test_problem_calculator() - val (language, functionalHandle, seedPrompt) = scala(name) - test(name, language, description, seedPrompt, functionalHandle) - } - - private fun scala(name: String) = - Triple("scala", "def main", """object $name {\n""") - - private fun javascript(name: String) = - Triple("js", "function main", """function $name() {\n""") - - @Test - fun javascript_test() { - if (!canRunTests()) return - val (name, description) = test_problem_calculator() - val (language, functionalHandle, seedPrompt) = javascript(name) - test(name, language, description, seedPrompt, functionalHandle) - } - - private fun python(name: String) = - Triple("py", "def main", """def $name():\n""") - - @Test - fun python_test() { - if (!canRunTests()) return - val (name, description) = test_problem_calculator() - val (language, functionalHandle, seedPrompt) = python(name) - test(name, language, description, seedPrompt, functionalHandle) - } - - private fun test_problem_calculator(): Pair> { - return Pair( - "String_Calculator", - listOf( - // First, two simple directives - "Create a utility function to find all simple addition expressions in a string and replace them with the calculated result.", - "Create a utility function to find all simple multiplication expressions in a string and replace them with the calculated result", - // This directive is more complex, but can be solved by chaining the previous two directives - "Implement a utility function to interpret simple math expressions.", - // Finally, we can test the entire class - "Implement a static main method that tests each class member and validates the output." - ) - ) - } - - - private fun test( - name: String, - language: String, - description: List, - seedPrompt: String, - functionalHandle: String, - question: String = "What is the big-O runtime and why?" - ) { - val reportPrefix = "${name}_${language}_" - val testOutputFile = File(outputDir, "${name}_${language}.md") - PrintWriter(FileOutputStream(testOutputFile)).use { out -> - out.println( - """ - - # $name - - In this test we will used AI Coding Assistant to implement the $name class to solve the following problem: - - """.trimIndent() - ) - out.println("```\n${description.toString().let { /*escapeHtml4*/(it)/*.indent(" ")*/ }}\n```") - newFile("$name.$language") - - - out.println( - """ - - ## Implementation - - The first step is to translate the problem into code. We can do this by using the "Insert Implementation" command. - - """.trimIndent() - ) - click("""//div[@class="EditorComponentImpl"]""") - keyboard.selectAll() - keyboard.key(KeyEvent.VK_DELETE) - enterLines(seedPrompt) - - for (line in description) { - click("""//div[@class="EditorComponentImpl"]""") - newEndOfLine() - enterLines("// $line") - writeImage( - menuAction("Insert Implementation"), outputDir, - name, "${reportPrefix}menu", out - ) - awaitBackgroundProgress() - //keyboard.hotKey(KeyEvent.VK_SHIFT, KeyEvent.VK_UP) - //keyboard.hotKey(KeyEvent.VK_DELETE) - keyboard.hotKey(KeyEvent.VK_SHIFT, KeyEvent.VK_ALT, KeyEvent.VK_DOWN) // Move current line down - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_ALT, KeyEvent.VK_L) // Reformat - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_S) // Save - } - - - out.println( - """ - - This results in the following code: - - ```$language""".trimIndent() - ) - out.println(FileUtils.readFileToString(File(testProjectPath, "src/$name.$language"), "UTF-8")) - out.println("```") - - out.println( - """ - - ## Rename Variables - - We can use the "Rename Variables" command to make the code more readable... - - """.trimIndent() - ) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_HOME) // Move to top - selectText( - getEditor(), functionalHandle - ) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_W) // Select function - writeImage( - menuAction("Rename Variables"), - outputDir, - name, "${reportPrefix}Rename_Variables", out - ) - awaitBackgroundProgress() - sleep(1000) - writeImage( - screenshot("""//div[@class="JDialog"]"""), - outputDir, - name, - "${reportPrefix}Rename_Variables_Dialog", - out - ) - click("//div[@text.key='button.ok']") - - - out.println( - """ - - ## Documentation Comments - - We also want good documentation for our code. We can use the "Add Documentation Comments" command to do - - """.trimIndent() - ) - selectText(getEditor(), functionalHandle) - writeImage( - menuAction("Doc Comments"), - outputDir, - name, "${reportPrefix}Add_Doc_Comments", out - ) - awaitBackgroundProgress() - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_HOME) // Move to top - writeImage( - screenshot("""//div[@class="IdeRootPane"]"""), - outputDir, - name, - "${reportPrefix}Add_Doc_Comments2", - out - ) - - - out.println( - """ - - ## Ad-Hoc Questions - - We can also ask questions about the code. For example, we can ask what the big-O runtime is for this code. - - """.trimIndent() - ) - selectText(getEditor(), functionalHandle) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_W) // Select function - writeImage( - menuAction("Ask a question"), - outputDir, - name, "${reportPrefix}Ask_Q", out - ) - click("""//div[@class="MultiplexingTextField"]""") - keyboard.enterText(question) - writeImage( - screenshot("""//div[@class="JDialog"]"""), - outputDir, - name, "${reportPrefix}Ask_Q2", out - ) - click("//div[@text.key='button.ok']") - awaitBackgroundProgress() - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_HOME) // Move to top - writeImage( - screenshot("""//div[@class="IdeRootPane"]"""), - outputDir, - name, "${reportPrefix}Ask_Q3", out - ) - - out.println( - """ - - ## Code Comments - - We can also add code comments to the code. This is useful for explaining the code to other developers. - - """.trimIndent() - ) - selectText(getEditor(), functionalHandle) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_W) // Select function - writeImage( - menuAction("Code Comments"), - outputDir, - name, "${reportPrefix}Add_Code_Comments", out - ) - awaitBackgroundProgress() - writeImage( - screenshot("""//div[@class="IdeRootPane"]"""), - outputDir, - name, - "${reportPrefix}Add_Code_Comments2", - out - ) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_ALT, KeyEvent.VK_L) // Reformat - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_S) // Save - out.println( - """ - - ```$language""".trimIndent() - ) - out.println(FileUtils.readFileToString(File(testProjectPath, "src/$name.$language"), "UTF-8")) - out.println( - """ - ``` - - """.trimIndent() - ) - - - // Close editor - click("""//div[@class="InplaceButton"]""") - } - } - - private fun newEndOfLine() { - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_END) - keyboard.hotKey(KeyEvent.VK_LEFT) - keyboard.hotKey(KeyEvent.VK_ENTER) - keyboard.hotKey(KeyEvent.VK_LEFT) - keyboard.hotKey(KeyEvent.VK_TAB) - } - - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/DocGen.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/DocGen.kt deleted file mode 100644 index 61423060..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/DocGen.kt +++ /dev/null @@ -1,131 +0,0 @@ -package com.github.simiacryptus.aicoder.test - -import org.apache.commons.io.FileUtils -import org.junit.jupiter.api.Test - -import java.io.File -import java.io.FileOutputStream -import java.io.PrintWriter -import java.util.* - -/** - * See Also: - * https://github.com/JetBrains/intellij-ui-test-robot - * https://joel-costigliola.github.io/assertj/swing/api/org/assertj/swing/core/Robot.html - */ -class DocGen { - - @Test - fun plugin_xml() { - val base = File("C:\\Users\\andre\\code\\aicoder\\intellij-aicoder") - if (!base.exists()) return - val input = - File(base, "src\\main\\resources\\META-INF\\plugin.xml") - val output = File(base, "actions.md") - val actions = loadActions(input) - - // Output a markdown table containing the action data - val writer = PrintWriter(FileOutputStream(output)) - - writer.println( - """ - - # Plaintext Actions - - Plaintext actions provide text processing features for any language. The following actions are available for plaintext in the AI Coder plugin: - - """.trimIndent() - ) - printTable2( - writer, - actions.filter { it["id"].toString().startsWith("com.github.simiacryptus.aicoder.actions.generic") } - .toTypedArray()) - - writer.println( - """ - - # Code Actions - - The following actions are available for coding in the AI Coder plugin: - - """.trimIndent() - ) - printTable2( - writer, - actions.filter { it["id"].toString().startsWith("com.github.simiacryptus.aicoder.actions.code") } - .toTypedArray()) - - writer.println( - """ - - # Markdown Actions - - Markdown Actions allow you to quickly and easily add list items, table columns, and more to your Markdown documents. - - """.trimIndent() - ) - printTable2( - writer, - actions.filter { it["id"].toString().startsWith("com.github.simiacryptus.aicoder.actions.markdown") } - .toTypedArray()) - - writer.println( - """ - - # Developer-Mode Actions - - Some actions are only available when the plugin is running in developer mode. These may be useful for debugging or development, but also contain experimental features that may not be fully functional. - - """.trimIndent() - ) - printTable2( - writer, - actions.filter { it["id"].toString().startsWith("com.github.simiacryptus.aicoder.actions.dev") } - .toTypedArray()) - - writer.close() - } - - private fun printTable2( - writer: PrintWriter, - actions: Array> - ) { - writer.println("| Text | Description |") - writer.println("| --- | --- |") - actions.forEach { action -> - val uiText = action["text"].toString().replace("_", "") - writer.println("| $uiText | ${action["long_description"]} |") - } - } - - private fun formatShortcut(shortcut: String): String { - return shortcut.trim() - .split(" ") - .map { it.substringAfter("=").replace("\"", "").trim() } - .joinToString(" + ") { "${it.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }}" } - } - - private fun loadActions(input: File): Array> { - val pluginXml = FileUtils.readFileToString(input, "UTF-8") - return (pluginXml.split("") } - + pluginXml.split("") }) - .filter { it.contains("").split("\n") - .joinToString(" ") { it.trim() }, - "shortcut" to if (action.contains("keyboard-shortcut")) { - formatShortcut(action.substringAfter("keymap=\"\$default\"").substringBefore("/>")) - } else { - "" - } - ) - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/UITest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/UITest.kt deleted file mode 100644 index f4b7cb25..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/UITest.kt +++ /dev/null @@ -1,149 +0,0 @@ -@file:Suppress("NAME_SHADOWING") - -package com.github.simiacryptus.aicoder.test - -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.canRunTests -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.documentJavaImplementation -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.documentMarkdownListAppend -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.documentTextAppend -import com.github.simiacryptus.aicoder.test.UITestUtil.Companion.outputDir -import org.junit.jupiter.api.Test -import java.io.File -import java.io.FileOutputStream -import java.io.PrintWriter - -/** - * See Also: - * https://github.com/JetBrains/intellij-ui-test-robot - * https://joel-costigliola.github.io/assertj/swing/api/org/assertj/swing/core/Robot.html - */ -class UITest { - - @Test - fun javaTests() { - if (!canRunTests()) return - val testOutputFile = File(outputDir, "java.md") - val out = PrintWriter(FileOutputStream(testOutputFile)) - out.use { out -> - documentJavaImplementation("Text_to_Morse", "Convert text to Morse code", out, outputDir) - //documentJavaImplementation("Prime_Numbers", "Print all prime numbers from 1 to 100", out, outputDir) - // documentJavaImplementation("Calculate_Pi", "Calculate Pi using the convergence of x = 1+sin x starting at x=3", out, buildDir) - // documentJavaImplementation("Java_8", "Demonstrate language features of Java 8", out, buildDir) - // documentJavaImplementation("Draw_A_Smile", "Draw a smiley face", out, buildDir) - // documentJavaImplementation("Fibonacci_Sequence", "Print the Fibonacci sequence up to 100", out, buildDir) - // documentJavaImplementation("Bubble_Sort", "Sort an array of integers using the bubble sort algorithm", out, buildDir) - // documentJavaImplementation("Factorial", "Calculate the factorial of a number", out, buildDir) - // documentJavaImplementation("Binary_Search", "Search an array of integers using the binary search algorithm", out, buildDir) - // documentJavaImplementation("Quick_Sort", "Sort an array of integers using the quick sort algorithm", out, buildDir) - // documentJavaImplementation("Linear_Search", "Search an array of integers using the linear search algorithm", out, buildDir) - // documentJavaImplementation("Insertion_Sort", "Sort an array of integers using the insertion sort algorithm", out, buildDir) - // documentJavaImplementation("Selection_Sort", "Sort an array of integers using the selection sort algorithm", out, buildDir) - // documentJavaImplementation("Merge_Sort", "Sort an array of integers using the merge sort algorithm", out, buildDir) - // documentJavaImplementation("Heap_Sort", "Sort an array of integers using the heap sort algorithm", out, buildDir) - // documentJavaImplementation("Shell_Sort", "Sort an array of integers using the shell sort algorithm", out, buildDir) - // documentJavaImplementation("Counting_Sort", "Sort an array of integers using the counting sort algorithm", out, buildDir) - // documentJavaImplementation("Radix_Sort", "Sort an array of integers using the radix sort algorithm", out, buildDir) - // documentJavaImplementation("Bucket_Sort", "Sort an array of integers using the bucket sort algorithm", out, buildDir) - // documentJavaImplementation("Bogo_Sort", "Sort an array of integers using the bogo sort algorithm", out, buildDir) - // documentJavaImplementation("Stooge_Sort", "Sort an array of integers using the stooge sort algorithm", out, buildDir) - // documentJavaImplementation("Cocktail_Sort", "Sort an array of integers using the cocktail sort algorithm", out, buildDir) - // documentJavaImplementation("Comb_Sort", "Sort an array of integers using the comb sort algorithm", out, buildDir) - // documentJavaImplementation("Gnome_Sort", "Sort an array of integers using the gnome sort algorithm", out, buildDir) - // documentJavaImplementation("Pancake_Sort", "Sort an array of integers using the pancake sort algorithm", out, buildDir) - // documentJavaImplementation("Cycle_Sort", "Sort an array of integers using the cycle sort algorithm", out, buildDir) - // documentJavaImplementation("Odd_Even_Sort", "Sort an array of integers using the odd-even sort algorithm", out, buildDir) - // documentJavaImplementation("Sleep_Sort", "Sort an array of integers using the sleep sort algorithm", out, buildDir) - // documentJavaImplementation("Binary_Tree_Sort", "Sort an array of integers using the binary tree sort algorithm", out, buildDir) - // documentJavaImplementation("Tim_Sort", "Sort an array of integers using the tim sort algorithm", out, buildDir) - // documentJavaImplementation("Pigeonhole_Sort", "Sort an array of integers using the pigeonhole sort algorithm", out, buildDir) - // documentJavaImplementation("Strand_Sort", "Sort an array of integers using the strand sort algorithm", out, buildDir) - // documentJavaImplementation("Bead_Sort", "Sort an array of integers using the bead sort algorithm", out, buildDir) - // documentJavaImplementation("Bitonic_Sort", "Sort an array of integers using the bitonic sort algorithm", out, buildDir) - // documentJavaImplementation("Tournament_Sort", "Sort an array of integers using the tournament sort algorithm", out, buildDir) - // documentJavaImplementation("Spread_Sort", "Sort an array of integers using the spread sort algorithm", out, buildDir) - // documentJavaImplementation("Library_Sort", "Sort an array of integers using the library sort algorithm", out, buildDir) - // documentJavaImplementation("Patience_Sort", "Sort an array of integers using the patience sort algorithm", out, buildDir) - // documentJavaImplementation("Smooth_Sort", "Sort an array of integers using the smooth sort algorithm", out, buildDir) - // documentJavaImplementation("American_Flag_Sort", "Sort an array of integers using the american flag sort algorithm", out, buildDir) - // documentJavaImplementation("Binary_Insertion_Sort", "Sort an array of integers using the binary insertion sort algorithm", out, buildDir) - // documentJavaImplementation("Block_Sort", "Sort an array of integers using the block sort algorithm", out, buildDir) - // documentJavaImplementation("Bozosort", "Sort an array of integers using the bozosort algorithm", out, buildDir) - // documentJavaImplementation("Brick_Sort", "Sort an array of integers using the brick sort algorithm", out, buildDir) - // documentJavaImplementation("Cocktail_Shaker_Sort", "Sort an array of integers using the cocktail shaker sort algorithm", out, buildDir) - // documentJavaImplementation("Gravity_Sort", "Sort an array of integers using the gravity sort algorithm", out, buildDir) - // documentJavaImplementation("Library_Sort", "Sort an array of integers using the library sort algorithm", out, buildDir) - // documentJavaImplementation("Pancake_Sorting", "Sort an array of integers using the pancake sorting algorithm", out, buildDir) - // documentJavaImplementation("Permutation_Sort", "Sort an array of integers using the permutation sort algorithm", out, buildDir) - // documentJavaImplementation("Postman_Sort", "Sort an array of integers using the postman sort algorithm", out, buildDir) - // documentJavaImplementation("Sleep_Sort", "Sort an array of integers using the sleep sort algorithm", out, buildDir) - // documentJavaImplementation("Spaghetti_Sort", "Sort an array of integers using the spaghetti sort algorithm", out, buildDir) - // documentJavaImplementation("Staircase_Sort", "Sort an array of integers using the staircase sort algorithm", out, buildDir) - // documentJavaImplementation("Strand_Sort", "Sort an array of integers using the strand sort algorithm", out, buildDir) - // documentJavaImplementation("Tree_Sort", "Sort an array of integers using the tree sort algorithm", out, buildDir) - // documentJavaImplementation("UnShuffle_Sort", "Sort an array of integers using the unshuffle sort algorithm", out, buildDir) - // documentJavaImplementation("Binary_Indexed_Tree", "Implement a binary indexed tree", out, buildDir) - // documentJavaImplementation("Binary_Search_Tree", "Implement a binary search tree", out, buildDir) - // documentJavaImplementation("AVL_Tree", "Implement an AVL tree", out, buildDir) - // documentJavaImplementation("Red_Black_Tree", "Implement a red-black tree", out, buildDir) - // documentJavaImplementation("Splay_Tree", "Implement a splay tree", out, buildDir) - // documentJavaImplementation("Trie", "Implement a trie", out, buildDir) - // documentJavaImplementation("KD_Tree", "Implement a KD tree", out, buildDir) - // documentJavaImplementation("B_Tree", "Implement a B-tree", out, buildDir) - // documentJavaImplementation("Binary_Heap", "Implement a binary heap", out, buildDir) - // documentJavaImplementation("Fibonacci_Heap", "Implement a Fibonacci heap", out, buildDir) - // documentJavaImplementation("Hash_Table", "Implement a hash table", out, buildDir) - // documentJavaImplementation("Graph", "Implement a graph", out, buildDir) - // documentJavaImplementation("Disjoint_Set", "Implement a disjoint set", out, buildDir) - // documentJavaImplementation("Priority_Queue", "Implement a priority queue", out, buildDir) - // documentJavaImplementation("Stack", "Implement a stack", out, buildDir) - // documentJavaImplementation("Queue", "Implement a queue", out, buildDir) - // documentJavaImplementation("Linked_List", "Implement a linked list", out, buildDir) - // documentJavaImplementation("Circular_Linked_List", "Implement a circular linked list", out, buildDir) - // documentJavaImplementation("Doubly_Linked_List", "Implement a doubly linked list", out, buildDir) - // documentJavaImplementation("Array_List", "Implement an array list", out, buildDir) - // documentJavaImplementation("Binary_Search_Tree", "Implement a binary search tree", out, buildDir) - // documentJavaImplementation("AVL_Tree", "Implement an AVL tree", out, buildDir) - // documentJavaImplementation("Red_Black_Tree", "Implement a red-black tree", out, buildDir) - // documentJavaImplementation("Splay_Tree", "Implement a splay tree", out, buildDir) - // documentJavaImplementation("Trie", "Implement a trie", out, buildDir) - // documentJavaImplementation("KD_Tree", "Implement a KD tree", out, buildDir) - // documentJavaImplementation("B_Tree", "Implement a B-tree", out, buildDir) - // documentJavaImplementation("Binary_Heap", "Implement a binary heap", out, buildDir) - // documentJavaImplementation("Fibonacci_Heap", "Implement a Fibonacci heap", out, buildDir) - // documentJavaImplementation("Hash_Table", "Implement a hash table", out, buildDir) - // documentJavaImplementation("Graph", "Implement a graph", out, buildDir) - // documentJavaImplementation("Disjoint_Set", "Implement a disjoint set", out, buildDir) - // documentJavaImplementation("Priority_Queue", "Implement a priority queue", out, buildDir) - // documentJavaImplementation("Stack", "Implement a stack", out, buildDir) - // documentJavaImplementation("Queue", "Implement a queue", out, buildDir) - // documentJavaImplementation("Linked_List", "Implement a linked list", out, buildDir) - // documentJavaImplementation("Circular_Linked_List", "Implement a circular linked list", out, buildDir) - // documentJavaImplementation("Doubly_Linked_List", "Implement a doubly linked list", out, buildDir) - // documentJavaImplementation("Array_List", "Implement an array list", out, buildDir) - // documentJavaImplementation("Binary_Search_Tree", "Implement a binary search tree", out, buildDir) - // documentJavaImplementation("AVL_Tree", "Implement an AVL tree", out, buildDir) - // documentJavaImplementation("Red_Black_Tree", "Implement a red-black tree", out, buildDir) - // documentJavaImplementation("Splay_Tree", "Implement a splay tree", out, buildDir) - } - } - - @Test - fun markdownTests() { - if (!canRunTests()) return - val testOutputFile = File(outputDir, "markdown.md") - val out = PrintWriter(FileOutputStream(testOutputFile)) - //documentMarkdownTableOps("State_Details", "Data Table of State Details", out, outputDir) - documentMarkdownListAppend("Puppy_Playtime", "Top 10 Best Ways to Play with Puppies", arrayOf(), out, outputDir) - out.close() // Close file - } - - @Test - fun plaintextTests() { - if (!canRunTests()) return - val testOutputFile = File(outputDir, "plaintext.md") - val out = PrintWriter(FileOutputStream(testOutputFile)) - documentTextAppend("Once_Upon_A_Time", "Once upon a time", out, outputDir) - out.close() // Close file - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/UITestUtil.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/UITestUtil.kt deleted file mode 100644 index 9d56d208..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/UITestUtil.kt +++ /dev/null @@ -1,772 +0,0 @@ -package com.github.simiacryptus.aicoder.test - -import com.intellij.remoterobot.RemoteRobot -import com.intellij.remoterobot.fixtures.ComponentFixture -import com.intellij.remoterobot.fixtures.dataExtractor.RemoteText -import com.intellij.remoterobot.search.locators.byXpath -import com.intellij.remoterobot.utils.Keyboard -import com.jetbrains.rd.util.firstOrNull -import org.apache.commons.io.FileUtils -import java.awt.Point - -import java.awt.event.KeyEvent -import java.awt.image.BufferedImage -import java.io.File -import java.io.FileOutputStream -import java.io.PrintWriter -import java.lang.Thread.sleep -import javax.imageio.ImageIO - -/** - * See Also: - * https://github.com/JetBrains/intellij-ui-test-robot - * https://joel-costigliola.github.io/assertj/swing/api/org/assertj/swing/core/Robot.html - */ -class UITestUtil { - - companion object { - - val outputDir = File("C:\\Users\\andre\\code\\intellij-aicoder\\build") - val testProjectPath = File("C:\\Users\\andre\\ideTest\\TestProject") - private const val testIdeUrl = "http://127.0.0.1:8082" - private val robot = RemoteRobot(testIdeUrl) - val keyboard = Keyboard(robot) - - /** - * - * Creates a new file with the given name. - * - * @param name The name of the file to create. - */ - fun newFile(name: String) { - click("""//div[@class="ProjectViewTree"]""") - keyboard.key(KeyEvent.VK_RIGHT) - keyboard.enterText("src") - keyboard.key(KeyEvent.VK_CONTEXT_MENU) - click( - "//div[contains(@text.key, 'group.NewGroup.text')]", - "//div[contains(@text.key, 'group.WeighingNewGroup.text')]" - ) - sleep(500) - click("""//div[@class="HeavyWeightWindow"][.//div[@class="MyMenu"]]//div[@class="HeavyWeightWindow"]//div[contains(@text.key, 'group.FileMenu.text')]""") - keyboard.enterText(name) - keyboard.enter() - sleep(500) - } - - private fun isStarted(): Boolean = - robot.findAll( - ComponentFixture::class.java, - byXpath("""//div[contains(@accessiblename.key, 'editor.accessible.name')]""") - ).isNotEmpty() - - private fun isStillRunning(): Boolean { - val resultText = - componentText("//div[contains(@accessiblename.key, 'editor.accessible.name')]") - return !(resultText.contains("Process finished")) - } - - - private fun componentText(s: String): String { - return getLines(getComponent(s)) - } - - private fun getLines(element: ComponentFixture): String { - val lines = element.data.getAll().groupBy { it.point.y } - return lines.toList().sortedBy { it.first }.map { it.second } - .map { it.toList().sortedBy { it.point.x }.map { it.text }.reduce { a, b -> a + b } } - .reduceOrNull { a, b -> a + "\n" + b }.orEmpty() - } - - private fun findText(element: ComponentFixture, text: String): Pair? { - val lines: Map> = element.data.getAll().groupBy { it.point.y } - val line = - lines.filter { it.value.map { it.text }.reduce { a, b -> a + b }.contains(text) }.firstOrNull()?.value - ?: return null - val index = line.map { it.text }.reduce { a, b -> a + b }.indexOf(text) - val lineBuffer = line.toMutableList() - var left = index - while (left > 0) { - val first = lineBuffer.first() - if (first.text.length <= left) { - left -= first.text.length - lineBuffer.removeAt(0) - } - } - val leftPoint = lineBuffer.first().point - left += text.length - var rightPoint: Point = leftPoint - while (left > 0) { - val first = lineBuffer.first() - if (first.text.length <= left) { - left -= first.text.length - rightPoint = lineBuffer.removeAt(0).point - } - } - if (lineBuffer.isNotEmpty()) { - rightPoint = lineBuffer.first().point - } - return Pair(leftPoint, rightPoint) - } - - fun selectText(element: ComponentFixture, text: String) { - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_HOME) - var findText = findText(element, text) - var pages = 0 - while (null == findText && pages++ < 10) { - keyboard.hotKey(KeyEvent.VK_PAGE_DOWN) - findText = findText(element, text) - } - val (leftPoint: Point, rightPoint: Point) = findText ?: throw Exception("Could not find text $text") - element.runJs("robot.pressMouse(component, new Point(${leftPoint.x}, ${leftPoint.y}))") - element.runJs("robot.moveMouse(component, new Point(${rightPoint.x}, ${rightPoint.y}))") - element.runJs("robot.releaseMouseButtons()") - } - - private fun clickText(element: ComponentFixture, text: String) { - val (leftPoint, _) = findText(element, text) ?: throw Exception("Could not find text $text") - element.runJs("robot.click(component, new Point(${leftPoint.x}, ${leftPoint.y}))") - } - - private fun implementCode(prompt: String): BufferedImage { - click("""//div[@class="EditorComponentImpl"]""") - keyboard.selectAll() - keyboard.key(KeyEvent.VK_DELETE) - enterLines(prompt) - val image = menuAction("Insert Implementation") - awaitBackgroundProgress() - return image - } - - fun menuAction(menuText: String): BufferedImage { - keyboard.key(KeyEvent.VK_CONTEXT_MENU) - sleep(500) - val aiCoderMenuItem = getComponent("//div[@text='AI Coder']") - aiCoderMenuItem.click() - val point1 = aiCoderMenuItem.locationOnScreen - sleep(500) - val submenu = - getComponent("""//div[@class="HeavyWeightWindow"][.//div[@class="MyMenu"]]//div[@class="HeavyWeightWindow"]//div[contains(@text, '$menuText')]""") - val point2 = submenu.locationOnScreen - submenu.runJs("robot.moveMouse(new Point(${point2.x}, ${point1.y}))") - submenu.runJs("robot.moveMouse(component)") - val image = screenshot("""//div[@class="IdeRootPane"]""") - submenu.click() - return image - } - - /** - * - * Awaits the completion of a running process. - * - * This function will wait until the process is started, then wait until it is finished. - * It will also print out the total time the process took to complete. - */ - private fun awaitRunCompletion() { - val timeout = 1 * 60 * 1000 - val startOverall = System.currentTimeMillis() - - while (!isStarted()) { - sleep(1) - if (System.currentTimeMillis() - startOverall > timeout) { - throw RuntimeException("Timeout waiting for process to start") - } - } - - val start = System.currentTimeMillis() - println("Process started") - - while (isStillRunning()) { - sleep(100) - if (System.currentTimeMillis() - startOverall > timeout) { - throw RuntimeException("Timeout waiting for process to end") - } - } - - val end = System.currentTimeMillis() - println("Process ended after ${(end - start) / 1000.0}") - } - - fun awaitBackgroundProgress() { - // Await a background task - it must be open then closed - val timeout = 1 * 60 * 1000 - val startOverall = System.currentTimeMillis() - while (!isBackgroundProgressOpen()) { - sleep(100) - if (System.currentTimeMillis() - startOverall > timeout) { - throw RuntimeException("Timeout waiting for background progress to open") - } - } - val start = System.currentTimeMillis() - println("Background progress opened") - while (isBackgroundProgressOpen()) { - sleep(100) - if (System.currentTimeMillis() - start > timeout) { - throw RuntimeException("Timeout waiting for background progress to close") - } - } - val end = System.currentTimeMillis() - println("Background progress closed after ${(end - start) / 1000.0}") - } - - private fun isBackgroundProgressOpen(): Boolean { - val progressPanel = robot.findAll( - ComponentFixture::class.java, - byXpath("""//div[@class="InlineProgressPanel"]""") - ) - if (progressPanel.isEmpty()) return false - val componentFixture = progressPanel.get(0) - val labels = componentFixture.data.getAll() - return labels.size != 0 - } - - fun documentJavaImplementation( - name: String, - directive: String, - out: PrintWriter, - reportDir: File - ) { - documentImplementation( - name = name, - out1 = out, - directive = directive, - extension = "java", - prompt = "public class $name {\\n // $directive and write a main method to test the code", - reportDir = reportDir, - language = "java", - selector = "static void main" - ) - } - - private fun documentImplementation( - name: String, - out1: PrintWriter, - directive: String, - extension: String, - prompt: String, - reportDir: File, - language: String, - selector: String - ) { - val reportPrefix = "${name}_${language}_" - val testOutputFile = File(outputDir, "$reportPrefix$name.md") - - PrintWriter(FileOutputStream(testOutputFile)).use { report -> - out1.println("[$directive ($language)]($reportPrefix$name.md)\n\n") - - report.println( - """ - - # $name - - In this test we will used AI Coding Assistant to implement the $name class to solve the following problem: - - """.trimIndent() - ) - report.println("```\n$directive\n```") - newFile("$name.$extension") - - - report.println( - """ - - ## Implementation - - The first step is to translate the problem into code. We can do this by using the "Insert Implementation" command. - - """.trimIndent() - ) - val image = implementCode(prompt) - writeImage(image, reportDir, name, "${reportPrefix}menu", report) - keyboard.hotKey(KeyEvent.VK_SHIFT, KeyEvent.VK_UP) - keyboard.hotKey(KeyEvent.VK_DELETE) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_ALT, KeyEvent.VK_L) // Reformat - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_S) // Save - report.println( - """ - - This results in the following code: - - ```$language""".trimIndent() - ) - report.println(FileUtils.readFileToString(File(testProjectPath, "src/$name.$extension"), "UTF-8")) - report.println("```") - - - report.println( - """ - - ## Execution - - This code can be executed by pressing the "Run" button in the top right corner of the IDE. - What could possibly go wrong? - - """.trimIndent() - ) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_SHIFT, KeyEvent.VK_F10) // Run - awaitRunCompletion() - report.println( - """ - - ```""".trimIndent() - ) - report.println(componentText("//div[contains(@accessiblename.key, 'editor.accessible.name')]")) - report.println( - """ - ``` - """.trimIndent() - ) - writeImage( - screenshot("""//div[@class="IdeRootPane"]"""), - reportDir, - name, - "${reportPrefix}result", - report - ) - // Close run tab - sleep(100) - clickr("""//div[@class="ContentTabLabel"]""") - sleep(100) - click("//div[contains(@text.key, 'action.CloseContent.text')]") - sleep(100) - - - report.println( - """ - - ## Rename Variables - - The code is not very readable. We can use the "Rename Variables" command to make it more readable... - - """.trimIndent() - ) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_HOME) // Move to top - selectText(getEditor(), selector) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_W) // Select function - writeImage(menuAction("Rename Variables"), reportDir, name, "${reportPrefix}Rename_Variables", report) - awaitBackgroundProgress() - sleep(1000) - writeImage( - screenshot("""//div[@class="JDialog"]"""), - reportDir, - name, - "${reportPrefix}Rename_Variables_Dialog", - report - ) - click("//div[@text.key='button.ok']") - - - report.println( - """ - - ## Documentation Comments - - We also want good documentation for our code. We can use the "Add Documentation Comments" command to do this. - - """.trimIndent() - ) - selectText(getEditor(), selector) - writeImage(menuAction("Doc Comments"), reportDir, name, "${reportPrefix}Add_Doc_Comments", report) - awaitBackgroundProgress() - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_HOME) // Move to top - writeImage( - screenshot("""//div[@class="IdeRootPane"]"""), - reportDir, - name, - "${reportPrefix}Add_Doc_Comments2", - report - ) - - - report.println( - """ - - ## Ad-Hoc Questions - - We can also ask questions about the code. For example, we can ask what the big-O runtime is for this code. - - """.trimIndent() - ) - selectText(getEditor(), selector) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_W) // Select function - writeImage(menuAction("Ask a question"), reportDir, name, "${reportPrefix}Ask_Q", report) - click("""//div[@class="MultiplexingTextField"]""") - keyboard.enterText("What is the big-O runtime and why?") - writeImage(screenshot("""//div[@class="JDialog"]"""), reportDir, name, "${reportPrefix}Ask_Q2", report) - click("//div[@text.key='button.ok']") - awaitBackgroundProgress() - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_HOME) // Move to top - writeImage( - screenshot("""//div[@class="IdeRootPane"]"""), - reportDir, - name, - "${reportPrefix}Ask_Q3", - report - ) - - report.println( - """ - - ## Code Comments - - We can also add code comments to the code. This is useful for explaining the code to other developers. - - """.trimIndent() - ) - selectText(getEditor(), selector) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_W) // Select function - writeImage(menuAction("Code Comments"), reportDir, name, "${reportPrefix}Add_Code_Comments", report) - awaitBackgroundProgress() - writeImage( - screenshot("""//div[@class="IdeRootPane"]"""), - reportDir, - name, - "${reportPrefix}Add_Code_Comments2", - report - ) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_ALT, KeyEvent.VK_L) // Reformat - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_S) // Save - report.println( - """ - - ```$language""".trimIndent() - ) - report.println(FileUtils.readFileToString(File(testProjectPath, "src/$name.$extension"), "UTF-8")) - report.println( - """ - ``` - - """.trimIndent() - ) - - - report.println( - """ - - ## Conversion to other languages - - ### JavaScript - - We can also convert the code to other languages. For example, we can convert the code to JavaScript. - - """.trimIndent() - ) - clickText(getComponent("""//div[@class="ProjectViewTree"]"""), name) - menuAction("Convert To") - keyboard.hotKey(KeyEvent.VK_DOWN) - writeImage( - screenshot("""//div[@class="IdeRootPane"]"""), - reportDir, - name, - "${reportPrefix}Convert_to_js", - report - ) - keyboard.hotKey(KeyEvent.VK_ENTER) - while (!File(testProjectPath, "src/$name.js").exists()) { - sleep(1000) - } - report.println( - """ - - ```js""".trimIndent() - ) - report.println(FileUtils.readFileToString(File(testProjectPath, "src/$name.js"), "UTF-8")) - report.println( - """ - ``` - """.trimIndent() - ) - - - report.println( - """ - ### Conversion to Scala - - We can also convert the code to Scala. - - """.trimIndent() - ) - clickText(getComponent("""//div[@class="ProjectViewTree"]"""), name) - menuAction("Convert To") - keyboard.hotKey(KeyEvent.VK_DOWN) - keyboard.hotKey(KeyEvent.VK_DOWN) - writeImage( - screenshot("""//div[@class="IdeRootPane"]"""), - reportDir, - name, - "${reportPrefix}Convert_to_scala", - report - ) - keyboard.hotKey(KeyEvent.VK_ENTER) - while (!File(testProjectPath, "src/$name.scala").exists()) { - sleep(1000) - } - report.println( - """ - ```scala""".trimIndent() - ) - report.println(FileUtils.readFileToString(File(testProjectPath, "src/$name.scala"), "UTF-8")) - report.println( - """ - ``` - """.trimIndent() - ) - - // Close editor - click("""//div[@class="InplaceButton"]""") - } - } - - fun documentTextAppend( - name: String, - directive: String, - report: PrintWriter, - file: File - ) { - val reportPrefix = "${name}_" - report.println("") - report.println( - """ - # $name - - In this example, we'll use the "Append Text" command to add some text after our prompt. - - ``` - $directive - ``` - - """.trimIndent() - ) - newFile("$name.txt") - - click("""//div[@class="EditorComponentImpl"]""") - keyboard.selectAll() - keyboard.key(KeyEvent.VK_DELETE) - enterLines(directive) - keyboard.selectAll() - val image = menuAction("Append Text") - awaitBackgroundProgress() - writeImage(image, file, name, "${reportPrefix}menu", report) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_S) // Save - - report.println( - """ - - This generates the following text: - - ```""".trimIndent() - ) - report.println(FileUtils.readFileToString(File(testProjectPath, "src/$name.txt"), "UTF-8")) - report.println( - """ - ``` - - """.trimIndent() - ) - - - report.println( - """ - - ## Edit Text - - We can also edit the text using the "Edit Text" command. - - """.trimIndent() - ) - click("""//div[@class="EditorComponentImpl"]""") - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_A) // Select all - writeImage(menuAction("Edit Code"), file, name, "${reportPrefix}edit_text", report) - click("""//div[@class="MultiplexingTextField"]""") - keyboard.enterText("Translate into a series of haikus") - writeImage(screenshot("""//div[@class="JDialog"]"""), file, name, "${reportPrefix}edit_text_2", report) - keyboard.enter() - awaitBackgroundProgress() - writeImage(screenshot("""//div[@class="IdeRootPane"]"""), file, name, "${reportPrefix}result1", report) - - - report.println( - """ - - We can also replace text using the "Replace Options" command. - - """.trimIndent() - ) - - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_S) // Save - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_HOME) - var documentText = FileUtils.readFileToString(File(testProjectPath, "src/$name.txt"), "UTF-8") - val randomLine = - documentText.split("\n").map { it.trim() }.filter { it.length < 100 }.take(40).toTypedArray().random() - selectText(getEditor(), randomLine) - keyboard.hotKey(KeyEvent.VK_SHIFT, KeyEvent.VK_END) - writeImage(menuAction("Replace Options"), file, name, "${reportPrefix}replace_options", report) - awaitBackgroundProgress() - sleep(500) - writeImage( - screenshot("""//div[@class="JDialog"]"""), - file, - name, - "${reportPrefix}replace_options_2", - report - ) - sleep(500) - - keyboard.enter() - writeImage(screenshot("""//div[@class="IdeRootPane"]"""), file, name, "${reportPrefix}result2", report) - - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_S) // Save - documentText = FileUtils.readFileToString(File(testProjectPath, "src/$name.txt"), "UTF-8") - report.println( - """ - - Our text now looks like this: - - ```""".trimIndent() - ) - report.println(documentText) - report.println( - """ - ``` - - """.trimIndent() - ) - - - // Close editor - sleep(1000) - click("""//div[@class="InplaceButton"]""") - } - - fun getEditor() = getComponent("""//div[@class="EditorComponentImpl"]""") - - fun documentMarkdownListAppend( - name: String, - directive: String, - examples: Array, - out: PrintWriter, - file: File - ) { - val reportPrefix = "${name}_" - out.println( - """ - # $name - - In this demo, we add a list to a Markdown document, and then add items to the list. - - ``` - $directive - ``` - - """.trimIndent() - ) - newFile("$name.md") - - click("""//div[@class="EditorComponentImpl"]""") - keyboard.selectAll() - keyboard.key(KeyEvent.VK_DELETE) - enterLines(directive) - keyboard.enter() - keyboard.enter() - keyboard.enterText("1. ") - for (example in examples) { - keyboard.enterText(example) - keyboard.enter() - } - keyboard.selectAll() - writeImage(menuAction("Append Text"), file, name, "${reportPrefix}append_text", out) - awaitBackgroundProgress() - - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_S) // Save - out.println( - """ - - ``` - """.trimIndent() - ) - out.println(FileUtils.readFileToString(File(testProjectPath, "src/$name.md"), "UTF-8")) - out.println( - """ - ``` - - """.trimIndent() - ) - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_END) // End of document - - writeImage(screenshot("""//div[@class="IdeRootPane"]"""), file, name, "${reportPrefix}result", out) - writeImage(menuAction("Add List Items"), file, name, "${reportPrefix}add_list_items", out) - awaitBackgroundProgress() - writeImage(screenshot("""//div[@class="IdeRootPane"]"""), file, name, "${reportPrefix}result2", out) - - keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_S) // Save - out.println( - """ - - ``` - """.trimIndent() - ) - out.println(FileUtils.readFileToString(File(testProjectPath, "src/$name.md"), "UTF-8")) - out.println( - """ - ``` - - """.trimIndent() - ) - - // Close editor - sleep(1000) - click("""//div[@class="InplaceButton"]""") - } - - - fun writeImage( - screenshot: BufferedImage, - file: File, - name: String, - subname: String, - out: PrintWriter - ) { - ImageIO.write(screenshot, "png", File(file, "$name-$subname.png")) - out.println( - """ - ![$subname](${name}-$subname.png) - - """.trimIndent() - ) - } - - fun screenshot(path: String) = - getComponent(path).getScreenshot() - - fun click(vararg path: String) { - getComponent(*path).click() - } - - private fun clickr(path: String) { - getComponent(path).rightClick() - } - - fun enterLines(input: String) { - input.split("\n").map { line -> { keyboard.enterText(line, 5) } }.reduce { a, b -> - { - a() - keyboard.enter() - b() - } - }() - } - - private fun getComponent(vararg paths: String) = - paths.flatMap { path -> - try { - listOf(robot.find(ComponentFixture::class.java, byXpath(path))) - } catch (ex: Throwable) { - listOf() - } - }.first() - - fun canRunTests() = outputDir.exists() && testProjectPath.exists() - - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/ActionTestBase.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/ActionTestBase.kt deleted file mode 100644 index d7c53276..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/ActionTestBase.kt +++ /dev/null @@ -1,120 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions - -import com.github.simiacryptus.aicoder.actions.FileContextAction -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.config.AppSettingsState -import com.github.simiacryptus.aicoder.test.util.MarkdownProcessor -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.intellij.mock.MockProgressIndicator -import com.simiacryptus.jopenai.models.OpenAIModels -import com.simiacryptus.jopenai.util.ClientUtil -import com.simiacryptus.util.JsonUtil -import org.junit.jupiter.api.Assertions -import java.io.File -import java.util.* - -open class ActionTestBase { - companion object { - - fun testScript_SelectionAction(selectionAction: SelectionAction, scriptPath: String) { - AppSettingsState.instance.apiKey = ClientUtil.keyMap.mapKeys { it.key }.toMutableMap() - AppSettingsState.instance.temperature = 0.0 - AppSettingsState.instance.smartModel = OpenAIModels.GPT4oMini.name - val input = - selectionAction.javaClass.getResourceAsStream(scriptPath)?.readAllBytes()?.toString(Charsets.UTF_8) - ?: "" - MarkdownProcessor.parse(input).forEach { markdownData -> - val jsonSection = markdownData.sections.find { it.title.lowercase() == "settings" } - val fromSection = markdownData.sections.find { it.title.lowercase() == "from" } - val toSection = markdownData.sections.find { it.title.lowercase() == "to" } - if (jsonSection != null && fromSection != null && toSection != null) { - val testData = JsonUtil.fromJson( - jsonSection.code, - SelectionAction.SelectionState::class.java - ) - var selectionState = testData.copy( - selectedText = fromSection.code, - language = ComputerLanguage.values().find { fromSection.codeType.equals(it.name, true) } - ) - if ((selectionState.selectionLength ?: 0) != 0) { - selectionState = selectionState.copy( - entireDocument = selectionState.selectedText, - selectedText = selectionState.selectedText?.substring( - selectionState.selectionOffset, - selectionState.selectionOffset + selectionState.selectionLength!! - ), - ) - } - var result = selectionAction.processSelection(null, selectionState, selectionAction.getConfig(null)) - if ((selectionState.selectionLength ?: 0) != 0) { - result = selectionState.entireDocument?.substring(0, selectionState.selectionOffset) + - result + - selectionState.entireDocument?.substring(selectionState.selectionOffset + selectionState.selectionLength!!) - } - Assertions.assertEquals( - toSection.code.trim().replace("\r\n", "\n"), - result.trim().replace("\r\n", "\n") - ) - } else { - throw RuntimeException("Invalid test data") - } - } - } - - inline fun testScript_FileContextAction( - selectionAction: FileContextAction, - scriptPath: String - ) { - AppSettingsState.instance.apiKey = ClientUtil.keyMap.mapKeys { it.key }.toMutableMap() - AppSettingsState.instance.temperature = 0.0 - AppSettingsState.instance.smartModel = OpenAIModels.GPT4oMini.name - val input = selectionAction.javaClass.getResourceAsStream(scriptPath)?.readAllBytes()?.toString(Charsets.UTF_8) ?: "" - var lastException: Throwable? = null - MarkdownProcessor.parse(input).forEach { markdownData -> - val configSection = markdownData.sections.find { it.title.lowercase() == "config" } - if (configSection != null) { - val configData = JsonUtil.fromJson(configSection.code, T::class.java) - val projectRoot = File("./build/temp/" + UUID.randomUUID().toString()).absoluteFile - - val inputFiles = - markdownData.sections.filter { it.title.lowercase().startsWith("from ") }.take(1).map { - val file = File(projectRoot, it.title.substring("from ".length)) - file.parentFile?.mkdirs() - file.writeText(it.code) - file - } - val selectionState = FileContextAction.SelectionState( - (inputFiles.firstOrNull() ?: File( - projectRoot, - "default" - )).apply { parentFile?.mkdirs() }.absoluteFile, - projectRoot.absoluteFile - ) - val result = selectionAction.processSelection(selectionState, configData, MockProgressIndicator()) - for (file in result) { - try { - val filePath = projectRoot.toPath().relativize(file.toPath()).toString() - val find = markdownData.sections.find { - it.title.lowercase().replace('\\', '/') == ("to " + filePath).lowercase() - .replace('\\', '/') - } - Assertions.assertTrue((find != null), "Missing section: to " + filePath) - Assertions.assertEquals( - find!!.code.trim().replace("\r\n", "\n"), - file.readText().trim().replace("\r\n", "\n") - ) - } catch (e: Throwable) { - e.printStackTrace() - lastException = e - } - } - } else { - throw RuntimeException("Invalid test data") - } - } - if (lastException != null) throw lastException!! - } - } - -} - diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/CommentsActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/CommentsActionTest.kt deleted file mode 100644 index 26da98ec..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/CommentsActionTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.legacy.CommentsAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class CommentsActionTest : ActionTestBase() { - - // @Test - fun testProcessing() { - testScript_SelectionAction(CommentsAction(), "/CommentsActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = CommentsAction() - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) -// Assertions.assertFalse(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = CommentsAction() - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - Assertions.assertEquals(Pair(0, 10), result) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/CustomEditActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/CustomEditActionTest.kt deleted file mode 100644 index 6fd97c57..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/CustomEditActionTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.code.CustomEditAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import com.intellij.openapi.project.Project -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class CustomEditActionTest : ActionTestBase() { - - private val instruction = "Add code comments" - - // @Test - fun testProcessing() { - testScript_SelectionAction(object : CustomEditAction() { - override fun getConfig(project: Project?): String { - return this@CustomEditActionTest.instruction - } - }, "/CustomEditActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = object : CustomEditAction() { - override fun getConfig(project: Project?): String { - return this@CustomEditActionTest.instruction - } - } - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = object : CustomEditAction() { - override fun getConfig(project: Project?): String { - return this@CustomEditActionTest.instruction - } - } - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - Assertions.assertEquals(Pair(0, 10), result) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/DescribeActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/DescribeActionTest.kt deleted file mode 100644 index 5a1f7c45..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/DescribeActionTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.code.DescribeAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class DescribeActionTest : ActionTestBase() { - - // @Test - fun testProcessing() { - testScript_SelectionAction(DescribeAction(), "/DescribeActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = DescribeAction() - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = DescribeAction() - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - Assertions.assertEquals(Pair(0, 10), result) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/DocActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/DocActionTest.kt deleted file mode 100644 index 975079c7..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/DocActionTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.legacy.DocAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test - -class DocActionTest : ActionTestBase() { - - // @Test - fun testProcessing() { - testScript_SelectionAction(DocAction(), "/DocActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = DocAction() - assertTrue(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) - assertFalse(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = DocAction() - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - assertEquals(Pair(0, 10), result) - } - -} - - diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/ImplementStubActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/ImplementStubActionTest.kt deleted file mode 100644 index 28d0206d..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/ImplementStubActionTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.legacy.ImplementStubAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class ImplementStubActionTest : ActionTestBase() { - - // @Test - fun testProcessing() { - testScript_SelectionAction(ImplementStubAction(), "/ImplementStubActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = ImplementStubAction() - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) - Assertions.assertFalse(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = ImplementStubAction() - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - Assertions.assertEquals(Pair(0, 10), result) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/InsertImplementationActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/InsertImplementationActionTest.kt deleted file mode 100644 index 23e1395a..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/InsertImplementationActionTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.legacy.InsertImplementationAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class InsertImplementationActionTest : ActionTestBase() { - - // @Test - fun testProcessing() { - testScript_SelectionAction(InsertImplementationAction(), "/InsertImplementationActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = InsertImplementationAction() - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) - Assertions.assertFalse(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = InsertImplementationAction() - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - Assertions.assertEquals(Pair(0, 10), result) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/RenameVariablesActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/RenameVariablesActionTest.kt deleted file mode 100644 index 6585144e..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/code/RenameVariablesActionTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.code - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.legacy.RenameVariablesAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class RenameVariablesActionTest : ActionTestBase() { - - // @Test - fun testProcessing() { - testScript_SelectionAction(object : RenameVariablesAction() { - override fun choose(renameSuggestions: Map): Set { - return renameSuggestions.keys.toSet() - } - }, "/RenameVariablesActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = RenameVariablesAction() - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) -// Assertions.assertFalse(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = RenameVariablesAction() - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - Assertions.assertEquals(Pair(0, 10), result) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/AnalogueFileActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/AnalogueFileActionTest.kt deleted file mode 100644 index a458f037..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/AnalogueFileActionTest.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.generic - -import com.github.simiacryptus.aicoder.actions.generic.GenerateRelatedFileAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase - -class AnalogueFileActionTest : ActionTestBase() { - // @Test - fun testProcessing() { - testScript_FileContextAction(GenerateRelatedFileAction(), "/AnalogueFileActionTest.md") - } -} - diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/AppendActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/AppendActionTest.kt deleted file mode 100644 index ee688d2d..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/AppendActionTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.generic - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.legacy.AppendTextWithChatAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class AppendActionTest : ActionTestBase() { - - // @Test - fun testProcessing() { - testScript_SelectionAction(AppendTextWithChatAction(), "/AppendActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = AppendTextWithChatAction() - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = AppendTextWithChatAction() - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - Assertions.assertEquals(Pair(0, 10), result) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/CreateFileActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/CreateFileActionTest.kt deleted file mode 100644 index 18a5d503..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/CreateFileActionTest.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.generic - -import com.github.simiacryptus.aicoder.actions.generic.CreateFileFromDescriptionAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase - -class CreateFileActionTest : ActionTestBase() { - // @Test - fun testProcessing() { - testScript_FileContextAction(CreateFileFromDescriptionAction(), "/CreateFileActionTest.md") - } -} \ No newline at end of file diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/ReplaceOptionsActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/ReplaceOptionsActionTest.kt deleted file mode 100644 index 195ed1e6..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/generic/ReplaceOptionsActionTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.generic - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.legacy.ReplaceWithSuggestionsAction -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class ReplaceOptionsActionTest : ActionTestBase() { - - // @Test - fun testProcessing() { - testScript_SelectionAction(object : ReplaceWithSuggestionsAction() { - override fun choose(choices: List): String { - return choices.sorted().last() - } - }, "/ReplaceOptionsActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = ReplaceWithSuggestionsAction() - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = ReplaceWithSuggestionsAction() - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - Assertions.assertEquals(Pair(0, 10), result) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/markdown/MarkdownImplementActionTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/markdown/MarkdownImplementActionTest.kt deleted file mode 100644 index 0fb52a68..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/actions/markdown/MarkdownImplementActionTest.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.github.simiacryptus.aicoder.test.actions.markdown - -import com.github.simiacryptus.aicoder.actions.SelectionAction -import com.github.simiacryptus.aicoder.actions.markdown.MarkdownImplementActionGroup -import com.github.simiacryptus.aicoder.test.actions.ActionTestBase -import com.github.simiacryptus.aicoder.util.ComputerLanguage -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class MarkdownImplementActionTest : ActionTestBase() { - - // @Test - fun testProcessing() { - testScript_SelectionAction(object : MarkdownImplementActionGroup.MarkdownImplementAction("kotlin") { - override fun processSelection(state: SelectionState, config: String?): String { - return super.processSelection(state, config).trim().split("\n").drop(1).dropLast(1).joinToString("\n") - } - }, "/MarkdownImplementActionTest.md") - } - - @Test - fun testIsLanguageSupported() { - val docAction = MarkdownImplementActionGroup.MarkdownImplementAction("kotlin") -// Assertions.assertFalse(docAction.isLanguageSupported(ComputerLanguage.Kotlin)) - Assertions.assertTrue(docAction.isLanguageSupported(ComputerLanguage.Markdown)) -// Assertions.assertFalse(docAction.isLanguageSupported(ComputerLanguage.Text)) - } - - @Test - fun testEditSelection() { - val docAction = MarkdownImplementActionGroup.MarkdownImplementAction("kotlin") - val editorState = - SelectionAction.EditorState("fun hello() {\nprintln(\"Hello, world!\")\n}", 0, Pair(0, 10), null, arrayOf()) - val result = docAction.editSelection(editorState, 0, 10) - Assertions.assertEquals(Pair(0, 10), result) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/util/ApxPatchUtilTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/util/ApxPatchUtilTest.kt deleted file mode 100644 index 7fcfe72e..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/util/ApxPatchUtilTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.github.simiacryptus.aicoder.test.util - -import com.simiacryptus.diff.PatchUtil -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -class ApxPatchUtilTest { - private val patch = """ - --- IntArrayAppendFile.kt - +++ IntArrayAppendFileUpdated.kt - @@ -8,7 +8,7 @@ - val length = file.length() - //require(length > 0) { "Data file empty: {$}length" } - require(length < Int.MAX_VALUE) { "Data file too large: {$}length" } - - XElements(length/4) - + XElements(length/4) // Initialize length directly in the constructor - } - - fun append(values: IntArray) { - - if(isClosed) throw IllegalStateException("File is closed") - - val toBytes = value.toBytes() - - bufferedOutputStream.write(toBytes) - - length = length + 1 - + try { - + if(isClosed) throw IllegalStateException("File is closed") - + for (value in values) { - + val toBytes = value.toBytes() - + bufferedOutputStream.write(toBytes) - + } - + length = length + values.size - + } catch (e: IOException) { - + // Handle file I/O exception - + e.printStackTrace() - + } - } - """.trimIndent() - private val source = """ - package com.simiacryptus.util.files - - import java.io.File - - class IntArrayAppendFile(val file: File) { - - private var isClosed: Boolean = false - var length : XElements = run { - val length = file.length() - //require(length > 0) { "Data file empty: {$}length" } - require(length < Int.MAX_VALUE) { "Data file too large: {$}length" } - XElements(length/4) - } - - private val bufferedOutputStream by lazy { file.outputStream().buffered() } - fun append(value: Int) { - if(isClosed) throw IllegalStateException("File is closed") - val toBytes = value.toBytes() - bufferedOutputStream.write(toBytes) - length = length + 1 - } - - - fun close() { - isClosed = true - bufferedOutputStream.close() - } - - companion object { - } - } - """.trimIndent() - - @Test - fun testPatch() { - val result = PatchUtil.applyPatch(source, patch) - println(result) - Assertions.assertTrue(result.contains("for (value in values")) - } -} \ No newline at end of file diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/util/DiffMatchPatchTest.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/util/DiffMatchPatchTest.kt deleted file mode 100644 index ca5f6715..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/util/DiffMatchPatchTest.kt +++ /dev/null @@ -1,127 +0,0 @@ -package com.github.simiacryptus.aicoder.test.util - -import com.simiacryptus.diff.DiffMatchPatch -import com.simiacryptus.diff.DiffMatchPatch.Diff -import com.simiacryptus.diff.DiffMatchPatch.Operation.* -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import java.util.* - - -class DiffMatchPatchTest { - - @Test - fun testDiffMain() { - // Test equality - Assertions.assertEquals(mutableListOf(Diff(EQUAL, "test")), DiffMatchPatch.diff_main("test", "test", false)) - - // Test differences - val diffs = LinkedList() - diffs.add(Diff(DELETE, "Hello")) - diffs.add(Diff(INSERT, "Goodbye")) - diffs.add(Diff(EQUAL, " world.")) - Assertions.assertEquals( - mutableListOf( - Diff(DELETE, "Hell"), Diff(INSERT, "G"), Diff(EQUAL, "o"), Diff(INSERT, "odbye"), Diff(EQUAL, " world.") - ), DiffMatchPatch.diff_main("Hello world.", "Goodbye world.", false) - ) - } - - @Test - fun testDiffCommonPrefix() { - Assertions.assertEquals(0, DiffMatchPatch.diff_commonPrefix("abc", "xyz")) - Assertions.assertEquals(4, DiffMatchPatch.diff_commonPrefix("1234abcdef", "1234xyz")) - Assertions.assertEquals(4, DiffMatchPatch.diff_commonPrefix("1234", "1234xyz")) - } - - @Test - fun testDiffCommonSuffix() { - Assertions.assertEquals(0, DiffMatchPatch.diff_commonSuffix("abc", "xyz")) - Assertions.assertEquals(4, DiffMatchPatch.diff_commonSuffix("abcdef1234", "xyz1234")) - Assertions.assertEquals(4, DiffMatchPatch.diff_commonSuffix("1234", "xyz1234")) - } - - // @Test - fun testPatchMakeAndApply() { - val text1 = "The quick brown fox jumps over the lazy dog." - val text2 = "The quick red fox jumps over the tired dog." - val patches: LinkedList = DiffMatchPatch.patch_make(text1, text2) - val results: Array = DiffMatchPatch.patch_apply(patches, text1) - - Assertions.assertEquals(text2, results[0]) - val applied = results[1] as BooleanArray - for (b in applied) { - Assertions.assertTrue(b) - } - } - - // @Test - fun testPatchMakeWithDiffs() { - val text1 = "The quick brown fox jumps over the lazy dog." - val text2 = "That quick brown fox jumped over a lazy dog." - val diffs: LinkedList = DiffMatchPatch.diff_main(text1, text2, false) - val patches: LinkedList = DiffMatchPatch.patch_make(diffs) - - Assertions.assertFalse(patches.isEmpty()) - Assertions.assertEquals(diffs, patches.first().diffs) - } - - @Test - fun testPatchToText() { - val text1 = "The quick brown\n fox jumps over\n the lazy dog.\n" - val text2 = "The quick red\n fox jumps over\n the tired dog.\n" - if (text1 == null || text2 == null) { - throw IllegalArgumentException("Null inputs. (patch_make)") - } - // No diffs provided, compute our own. - // Set a deadline by which time the diff must be complete. - val deadline: Long - if (DiffMatchPatch.Diff_Timeout <= 0) { - deadline = Long.MAX_VALUE - } else { - deadline = System.currentTimeMillis() + (DiffMatchPatch.Diff_Timeout * 1000).toLong() - } - val diffs = DiffMatchPatch.diff_main(text1, text2, false /*true*/, deadline) - if (diffs.size > 2) { - DiffMatchPatch.diff_cleanupSemantic(diffs) - DiffMatchPatch.diff_cleanupEfficiency(diffs) - } - val patches: LinkedList = DiffMatchPatch.patch_make(text1, diffs) - val patchText: String = DiffMatchPatch.patch_toText(patches) - println(patchText) - - Assertions.assertFalse(patchText.isEmpty()) - Assertions.assertTrue(patchText.startsWith("@@ -1,"), patchText) - } - - @Test - fun testPatchFromText() { - val patchText = """@@ -1,8 +1,5 @@ --The quick -+That - brown -@@ -22,17 +19,17 @@ - jumps --over the lazy -+over a lazy - dog. -""" - val patches = DiffMatchPatch.patch_fromText(patchText) - - Assertions.assertFalse(patches.isEmpty()) - Assertions.assertEquals("The quick", patches.first().diffs.first().text) - } - - @Test - // expect IllegalArgumentException::class - fun testPatchFromTextWithInvalidInput() { - val invalidPatchText = """@@ -1,8 +1,5 @@ --The quick -+That - brown -""" - // This should throw an IllegalArgumentException due to the incomplete patch text - DiffMatchPatch.patch_fromText(invalidPatchText) - } - -} diff --git a/src/test/kotlin/com/github/simiacryptus/aicoder/test/util/MarkdownProcessor.kt b/src/test/kotlin/com/github/simiacryptus/aicoder/test/util/MarkdownProcessor.kt deleted file mode 100644 index 77fbe85a..00000000 --- a/src/test/kotlin/com/github/simiacryptus/aicoder/test/util/MarkdownProcessor.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.github.simiacryptus.aicoder.test.util - -object MarkdownProcessor { - - data class MarkdownData(val name: String, val sections: List
) - - data class Section(val title: String, val codeType: String, val code: String) - - @JvmStatic - fun parse(input: String): List { - val lines = input.split("\n") - val markdownDataList = mutableListOf() - - var name = "" - var title = "" - var codeType: String? = null - var code = "" - var sections = mutableListOf
() - - for (line in lines) { - when { - line.startsWith("# ") -> { - if (name.isNotEmpty()) { - markdownDataList.add(MarkdownData(name, sections)) - sections = mutableListOf() - } - name = line.removePrefix("# ").trim() - } - - line.startsWith("## ") -> { - title = line.removePrefix("## ").trim() - } - - line.startsWith("```") -> { - if (codeType == null) { - codeType = line.removePrefix("```").trim() - code = "" - } else { - if (title.isNotEmpty()) { - sections.add(Section(title, codeType, code.trim())) - } - codeType = null - } - } - - else -> code += "$line\n" - } - } - - // Add the last section - if (title.isNotEmpty()) { - sections.add(Section(title, codeType ?: "", code.trim())) - } - - // Add the last markdown data - if (name.isNotEmpty()) { - markdownDataList.add(MarkdownData(name, sections)) - } - - return markdownDataList - } - - fun toString(markdownDataList: List): String { - var output = "" - - for (markdownData in markdownDataList) { - output += "# ${markdownData.name}\n" - - for (section in markdownData.sections) { - output += "\n## ${section.title}\n\n```${section.codeType}\n${ - section.code.let { - /*escapeHtml4*/(it)/*.indent(" ")*/ - } - }\n```\n" - } - } - - return output - } -} - diff --git a/src/test/resources/AnalogueFileActionTest.md b/src/test/resources/AnalogueFileActionTest.md deleted file mode 100644 index 5d10b2fe..00000000 --- a/src/test/resources/AnalogueFileActionTest.md +++ /dev/null @@ -1,28 +0,0 @@ -# Simple Kotlin Comments Action Test - -## From main.kt - -```kotlin -fun main() { - println("Hello, World!") -} -``` - -## Config - -```json -{ - "directive": "translate to java" -} -``` - -## To new_file.java - -```java -public class NewFile { - public static void main(String[] args) { - System.out.println("Hello, World!"); - } -} -``` - diff --git a/src/test/resources/AppendActionTest.md b/src/test/resources/AppendActionTest.md deleted file mode 100644 index 0dc427d4..00000000 --- a/src/test/resources/AppendActionTest.md +++ /dev/null @@ -1,32 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```text -Lightning crashes in the background as the programmer smiles with unholy glee. -``` - -## To - -```text -Lightning crashes in the background as the programmer smiles with unholy glee.He knows that he has just unleashed a powerful and unstoppable code upon the world. The lines of code he has meticulously crafted will revolutionize the way people interact with technology. With each keystroke, he can feel the raw power surging through his veins, fueling his insatiable desire to create and innovate. - -As the thunder rumbles, the programmer's smile widens, reflecting the intensity of his excitement. The storm outside mirrors the storm of ideas brewing inside his mind. He envisions a future where his creation will transcend boundaries, pushing the limits of what is possible. - -With a final flourish, he compiles the code, unleashing it into the digital realm. The world will never be the same again. The programmer's unholy glee transforms into a sense of anticipation, as he eagerly awaits the impact his creation will have on the world. - -Little does he know, his creation will become a catalyst for change, inspiring countless others to push the boundaries of technology. The lightning crashes in the background, a symbol of the power and potential that lies within the programmer's creation. - -As the storm subsides, the programmer's smile remains, a testament to the passion and dedication that drives him. He knows that this is just the beginning, and that his journey as a programmer will continue to be filled with exhilarating challenges and groundbreaking discoveries. - -With a renewed sense of purpose, the programmer sets his sights on the next project, ready to embark on another adventure fueled by his unholy glee and the lightning that crashes in the background. -``` - diff --git a/src/test/resources/CommentsActionTest.md b/src/test/resources/CommentsActionTest.md deleted file mode 100644 index 9b6e48cc..00000000 --- a/src/test/resources/CommentsActionTest.md +++ /dev/null @@ -1,27 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```kotlin -fun main() { - println("Hello, World!") -} -``` - -## To - -```kotlin -fun main() { - // This is the main function - println("Hello, World!") // This prints 'Hello, World!' -} -``` - diff --git a/src/test/resources/CreateFileActionTest.md b/src/test/resources/CreateFileActionTest.md deleted file mode 100644 index e17d7525..00000000 --- a/src/test/resources/CreateFileActionTest.md +++ /dev/null @@ -1,19 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Config - -```json -{ - "directive": "Create a hello world java example" -} -``` - -## To default/HelloWorld.java - -```java -public class HelloWorld { - public static void main(String[] args) { - System.out.println("Hello, World!"); - } -} -``` diff --git a/src/test/resources/CustomEditActionTest.md b/src/test/resources/CustomEditActionTest.md deleted file mode 100644 index 549453c2..00000000 --- a/src/test/resources/CustomEditActionTest.md +++ /dev/null @@ -1,27 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```kotlin -fun main() { - println("Hello, World!") -} -``` - -## To - -```kotlin -// Print Hello, World! to the console -fun main() { - println("Hello, World!") -} -``` - diff --git a/src/test/resources/DescribeActionTest.md b/src/test/resources/DescribeActionTest.md deleted file mode 100644 index 4fb22823..00000000 --- a/src/test/resources/DescribeActionTest.md +++ /dev/null @@ -1,27 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```kotlin -fun main() { - println("Hello, World!") -} -``` - -## To - -```kotlin -This is a Kotlin code that prints "Hello, World!" to the console. - fun main() { - println("Hello, World!") -} -``` - diff --git a/src/test/resources/DocActionTest.md b/src/test/resources/DocActionTest.md deleted file mode 100644 index 41489868..00000000 --- a/src/test/resources/DocActionTest.md +++ /dev/null @@ -1,28 +0,0 @@ -# Simple Kotlin Doc Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```kotlin -fun main() { - println("Hello, World!") -} -``` - -## To - -```kotlin -fun main() { - println("Hello, World!") -}fun main() { - println("Hello, World!") -} -``` - diff --git a/src/test/resources/GenerateProjectActionTest.md b/src/test/resources/GenerateProjectActionTest.md deleted file mode 100644 index 3e0d9828..00000000 --- a/src/test/resources/GenerateProjectActionTest.md +++ /dev/null @@ -1,21 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Config - -```json -{ - "description": "Simple Hello World Application", - "drafts": 1, - "saveAlternates": true -} -``` - -## To default - -```java -public class HelloWorldApp { - public static void main(String[] args) { - System.out.println("Hello World!"); - } -} -``` \ No newline at end of file diff --git a/src/test/resources/GenerateStoryActionTest.md b/src/test/resources/GenerateStoryActionTest.md deleted file mode 100644 index d06c65e7..00000000 --- a/src/test/resources/GenerateStoryActionTest.md +++ /dev/null @@ -1,437 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Config - -```json -{ - "title": "How to write a book", - "description": "A software developer teaches a computer how to teach another computer how to write a book. They then teach another computer to use that computer to publish and sell books online. Chaos ensues. Society collapses. The world ends.", - "writingStyle": "First Person Narrative, Present Tense, 8th Grade Reading Level" -} -``` - -## To default\How to write a book_screenplay.md - -```markdown -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - -****: - - - -**Alice**: I can't believe we're still stuck in this office. - - -**Bob**: Yeah, it feels like we've been here forever. - - -**Charlie**: I miss the outside world. - - -**Eve**: Me too. I wish we could go back to normal. - - -**Mallory**: I don't think normal exists anymore. - - -**Alice**: What do you mean? - - -**Bob**: Yeah, what's going on? - - -**Charlie**: I heard there was a global collapse. - - -**Eve**: Everything just fell apart. - - -**Mallory**: No more governments, no more rules. - - -**Alice**: So what do we do now? - - -**Bob**: I guess we survive. - - -**Charlie**: We stick together. - - -**Eve**: And we find a way to rebuild. - - -**Mallory**: We can't give up. - - -**Alice**: Alice looks out the window and sees a group of survivors. - - -**Bob**: Look, there are others out there! - - -**Charlie**: We're not alone. - - -**Eve**: Maybe there's hope after all. - - -**Mallory**: Let's go talk to them. - - -**Alice**: We need to stick together. - - -**Bob**: Agreed. - - -**Charlie**: Let's go. - - -**Eve**: Together, we can rebuild. - - -**Mallory**: And create a new world. - - -**Alice**: A world where technology is our ally. - - -**Bob**: And chaos becomes order. - - -**Charlie**: Let's make it happen. - - -**Eve**: Together, we can change the world. - - -**Mallory**: Let's get started. - - -**Alice**: And so, our journey begins. - - -**Bob**: A journey to a new future. - - - -**Alice**: I can't believe we're still stuck in this office. - - -**Bob**: Yeah, it feels like we've been here forever. - - -**Charlie**: I miss the outside world. - - -**Eve**: Me too. I wish we could go back to normal. - - -**Mallory**: I don't think normal exists anymore. - - -**Alice**: What do you mean? - - -**Bob**: Yeah, what's going on? - - -**Charlie**: I heard there was a global collapse. - - -**Eve**: Everything just fell apart. - - -**Mallory**: No more governments, no more rules. - - -**Alice**: So what do we do now? - - -**Bob**: I guess we survive. - - -**Charlie**: We stick together. - - -**Eve**: And we find a way to rebuild. - - -**Mallory**: We can't give up. - - -**Alice**: Alice looks out the window and sees a group of survivors. - - -**Bob**: Look, there are others out there! - - -**Charlie**: We're not alone. - - -**Eve**: Maybe there's hope after all. - - -**Mallory**: Let's go talk to them. - - -**Alice**: We need to stick together. - - -**Bob**: Agreed. - - -**Charlie**: Let's go. - - -**Eve**: Together, we can rebuild. - - -**Mallory**: And create a new world. - - -**Alice**: A world where technology is our ally. - - -**Bob**: And chaos becomes order. - - -**Charlie**: Let's make it happen. - - -**Eve**: Together, we can change the world. - - -**Mallory**: Let's get started. - - -**Alice**: And so, our journey begins. - - -**Bob**: A journey to a new future. - - - -**Alice**: I can't believe we're still stuck in this office. - - -**Bob**: Yeah, it feels like we've been here forever. - - -**Charlie**: I miss the outside world. - - -**Eve**: Me too. I wish we could go back to normal. - - -**Mallory**: I don't think normal exists anymore. - - -**Alice**: What do you mean? - - -**Bob**: Yeah, what's going on? - - -**Charlie**: I heard there was a global collapse. - - -**Eve**: Everything just fell apart. - - -**Mallory**: No more governments, no more rules. - - -**Alice**: So what do we do now? - - -**Bob**: I guess we survive. - - -**Charlie**: We stick together. - - -**Eve**: And we find a way to rebuild. - - -**Mallory**: We can't give up. - - -**Alice**: Alice looks out the window and sees a group of survivors. - - -**Bob**: Look, there are others out there! - - -**Charlie**: We're not alone. - - -**Eve**: Maybe there's hope after all. - - -**Mallory**: Let's go talk to them. - - -**Alice**: We need to stick together. - - -**Bob**: Agreed. - - -**Charlie**: Let's go. - - -**Eve**: Together, we can rebuild. - - -**Mallory**: And create a new world. - - -**Alice**: A world where technology is our ally. - - -**Bob**: And chaos becomes order. - - -**Charlie**: Let's make it happen. - - -**Eve**: Together, we can change the world. - - -**Mallory**: Let's get started. - - -**Alice**: And so, our journey begins. - - -**Bob**: A journey to a new future. -``` - -## To default\How to write a book.md - -```markdown -Once upon a time, in a small town called Willowbrook, there lived a young girl named Emily. She was an ordinary girl with an extraordinary imagination. Every day after school, Emily would rush home to her room, where she would spend hours lost in the world of books and stories. - -One sunny afternoon, as Emily sat at her desk, she noticed a mysterious book tucked away on the top shelf. It was old and dusty, with a worn-out cover that seemed to hold a secret. Curiosity got the better of her, and she reached up to grab the book. - -As she opened the book, a gust of wind blew through the room, causing the pages to flutter. Suddenly, Emily found herself transported to a magical land filled with talking animals, enchanted forests, and hidden treasures. - -With each turn of the page, Emily's adventure grew more exciting. She met a wise old owl who guided her through the forest, a mischievous squirrel who led her to a hidden cave, and a friendly dragon who helped her solve a riddle. - -As the sun began to set, Emily realized that she had to find her way back home. With a heavy heart, she closed the book and said goodbye to her newfound friends. But she knew that she would never forget the incredible journey she had experienced. - -And so, Emily returned to her room, where she continued to explore the world of books and stories. She knew that no matter where her imagination took her, she would always find a home within the pages of a book. - -Emily woke up the next morning with a sense of excitement. She couldn't wait to continue her adventure in the magical land she had discovered. As she got ready for school, she couldn't help but think about the talking animals, the enchanted forests, and the hidden treasures. - -Throughout the day, Emily's mind wandered to the book and the incredible journey she had experienced. She found it hard to concentrate on her lessons, as her imagination kept taking her back to the world of the story. - -After school, Emily rushed home and went straight to her room. She opened the book and once again found herself transported to the magical land. This time, she decided to explore the enchanted forests and see what other wonders awaited her. - -As she walked through the forest, Emily marveled at the vibrant colors and the sweet scent of flowers. She could hear the chirping of birds and the rustling of leaves. It felt like she had stepped into a fairytale. - -Suddenly, she heard a soft voice calling her name. Emily turned around and saw a small, furry creature with bright blue eyes. It was a talking rabbit! - -The rabbit introduced itself as Benjamin and offered to be Emily's guide through the forest. Excitedly, Emily followed Benjamin as he hopped from one tree to another, showing her the hidden paths and secret spots. - -They came across a sparkling waterfall, where Emily splashed her face with the cool water. Benjamin told her that the water had magical properties and could grant wishes. Emily closed her eyes and made a wish for her adventure to never end. - -As they continued their journey, Emily and Benjamin encountered more talking animals. There was a wise old fox who shared stories of the forest's history, a playful deer who danced gracefully among the trees, and a mischievous squirrel who loved to play pranks. - -As the sun started to set, Emily knew it was time to return home. She thanked Benjamin and bid farewell to the enchanted forest. With a heavy heart, she closed the book and placed it back on the shelf. - -But Emily knew that her adventure was far from over. She couldn't wait to open the book again and continue exploring the magical land. And so, she went to bed with dreams of talking animals and enchanted forests, eagerly awaiting the next chapter of her extraordinary journey. -``` \ No newline at end of file diff --git a/src/test/resources/ImplementStubActionTest.md b/src/test/resources/ImplementStubActionTest.md deleted file mode 100644 index dcda5d4e..00000000 --- a/src/test/resources/ImplementStubActionTest.md +++ /dev/null @@ -1,26 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```kotlin -fun dotProduct(a: Array, b: Array): Double { - TODO("Not yet implemented") -} -``` - -## To - -```kotlin -fun dotProduct(a: Array, b: Array): Double { - return a.zip(b).map { (x, y) -> x * y }.sum() -} -``` - diff --git a/src/test/resources/InsertImplementationActionTest.md b/src/test/resources/InsertImplementationActionTest.md deleted file mode 100644 index 1960de94..00000000 --- a/src/test/resources/InsertImplementationActionTest.md +++ /dev/null @@ -1,42 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```kotlin -// Sum all the prime numbers less than 1000 -``` - -## To - -```kotlin -fun main() { - var sum = 0 - for (i in 2 until 1000) { - if (isPrime(i)) { - sum += i - } - } - println("The sum of all prime numbers less than 1000 is: $sum") -} - -fun isPrime(num: Int): Boolean { - if (num <= 1) { - return false - } - for (i in 2 until num) { - if (num % i == 0) { - return false - } - } - return true -} -``` - diff --git a/src/test/resources/MarkdownImplementActionTest.md b/src/test/resources/MarkdownImplementActionTest.md deleted file mode 100644 index eca93893..00000000 --- a/src/test/resources/MarkdownImplementActionTest.md +++ /dev/null @@ -1,42 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```markdown -Sum all the prime numbers up to 1000 -``` - -## To - -```kotlin -fun isPrime(n: Int): Boolean { - if (n <= 1) return false - for (i in 2 until n) { - if (n % i == 0) return false - } - return true -} - -fun sumPrimeNumbers(limit: Int): Int { - var sum = 0 - for (i in 2..limit) { - if (isPrime(i)) { - sum += i - } - } - return sum -} - -val limit = 1000 -val result = sumPrimeNumbers(limit) -println("The sum of prime numbers up to $limit is: $result") -``` - diff --git a/src/test/resources/PasteActionTest.md b/src/test/resources/PasteActionTest.md deleted file mode 100644 index 52f79472..00000000 --- a/src/test/resources/PasteActionTest.md +++ /dev/null @@ -1,34 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```kotlin -Print all the prime numbers between 1 and 1000. -``` - -## To - -```kotlin -fun isPrime(num: Int): Boolean { - if (num <= 1) return false - for (i in 2 until num) { - if (num % i == 0) return false - } - return true -} - -fun main() { - for (i in 1..1000) { - if (isPrime(i)) println(i) - } -} -``` - diff --git a/src/test/resources/QuestionActionTest.md b/src/test/resources/QuestionActionTest.md deleted file mode 100644 index f69b5b2b..00000000 --- a/src/test/resources/QuestionActionTest.md +++ /dev/null @@ -1,30 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```kotlin -fun main() { - println("Hello, World!") -} -``` - -## To - -```kotlin -/* - Question: How are you feeling? - Answer: I'm an AI, I don't have feelings. -*/ -fun main() { - println("Hello, World!") -} -``` - diff --git a/src/test/resources/RenameVariablesActionTest.md b/src/test/resources/RenameVariablesActionTest.md deleted file mode 100644 index 63692768..00000000 --- a/src/test/resources/RenameVariablesActionTest.md +++ /dev/null @@ -1,26 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "" -} -``` - -## From - -```kotlin -fun main() { - println("Hello, World!") -} -``` - -## To - -```kotlin -fun printHelloWorld() { - printLine("Greetings, Earth!") -} -``` - diff --git a/src/test/resources/ReplaceOptionsActionTest.md b/src/test/resources/ReplaceOptionsActionTest.md deleted file mode 100644 index a5b9e27c..00000000 --- a/src/test/resources/ReplaceOptionsActionTest.md +++ /dev/null @@ -1,24 +0,0 @@ -# Simple Kotlin Comments Action Test - -## Settings - -```json -{ - "indent": "", - "selectionOffset": 43, - "selectionLength": 10 -} -``` - -## From - -```text -Lightning crashes in the background as the programmer smiles with unholy glee. -``` - -## To - -```text -Lightning crashes in the background as the witch smiles with unholy glee. -``` -