├── .adr.json ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── new-framework-support.md └── workflows │ ├── cd.yaml │ └── ci.yaml ├── .gitignore ├── LICENSE ├── README.md ├── _fixtures └── governance │ └── api │ └── untitled │ └── src │ └── main │ └── java │ └── cc │ └── unitmesh │ └── untitled │ └── demo │ └── controller │ └── BlogController.java ├── agent └── rust │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ └── src │ ├── bin │ └── agent.rs │ ├── lib.rs │ └── rpc │ ├── client.rs │ ├── mod.rs │ ├── notification.rs │ ├── request.rs │ └── unit_rpc.rs ├── architecture ├── README.md ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── architecture │ │ ├── action │ │ ├── IOAction.kt │ │ ├── IOActionType.kt │ │ └── RefactoringAction.kt │ │ ├── layered │ │ ├── ArchitectureStyle.kt │ │ ├── Channel.kt │ │ └── LayeredStyle.kt │ │ └── style │ │ └── NameStyle.kt │ └── test │ ├── kotlin │ └── org │ │ └── archguard │ │ └── architecture │ │ ├── layered │ │ ├── ArchitectureStyleTest.kt │ │ └── ChannelTypeTest.kt │ │ └── style │ │ └── NamingStyleTest.kt │ └── resources │ └── testdata │ └── spring-hello-world │ ├── .gitignore │ ├── build.gradle.kts │ ├── settings.gradle.kts │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ └── DemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── demo │ └── DemoApplicationTests.java ├── build.gradle.kts ├── comate-cli ├── README.md ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── comate │ │ ├── cli │ │ └── Main.kt │ │ └── command │ │ ├── ComateCommand.kt │ │ └── CommandEmbedMap.kt │ └── test │ └── kotlin │ └── org │ └── archguard │ └── comate │ └── command │ └── ComateCommandTest.kt ├── comate-core ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── comate │ │ ├── action │ │ ├── ApiGenPrompter.kt │ │ ├── ApiGovernancePrompter.kt │ │ ├── DesignSystemPrompter.kt │ │ ├── FoundationGovernancePrompter.kt │ │ ├── IntroductionCodePrompt.kt │ │ ├── LayeredStylePrompt.kt │ │ ├── base │ │ │ └── BaseTemplate.kt │ │ └── model │ │ │ └── ApiResult.kt │ │ ├── code │ │ ├── CodeDataStructExt.kt │ │ ├── FunctionCallChain.kt │ │ ├── ProjectDependency.kt │ │ └── ServicesMap.kt │ │ ├── command │ │ └── ComateContext.kt │ │ ├── document │ │ ├── IntroductionVisitor.kt │ │ └── ReadmeParser.kt │ │ ├── dynamic │ │ ├── DynamicContext.kt │ │ ├── DynamicContextFactory.kt │ │ ├── DynamicContextManager.kt │ │ └── functions │ │ │ ├── DesignSystemWithRequirementFunction.kt │ │ │ ├── DyFunction.kt │ │ │ ├── FoundationSpecGovernanceFunction.kt │ │ │ ├── InitializeSystemFunction.kt │ │ │ ├── IntroduceSystemFunction.kt │ │ │ └── RestApiGovernanceFunction.kt │ │ ├── model │ │ ├── DomainModelScanner.kt │ │ └── UmlConverter.kt │ │ ├── strategy │ │ ├── BasicPromptStrategy.kt │ │ ├── CodePromptStrategy.kt │ │ └── Strategy.kt │ │ └── wrapper │ │ └── ComateArchguardContext.kt │ └── test │ ├── kotlin │ └── org │ │ └── archguard │ │ └── comate │ │ ├── action │ │ ├── ApiGovernancePrompterTest.kt │ │ ├── DesignSystemPrompterTest.kt │ │ ├── IntroductionPrompterTest.kt │ │ └── LayeredStylePromptTest.kt │ │ ├── code │ │ ├── FunctionCallChainTest.kt │ │ └── ProjectDependencyKtTest.kt │ │ ├── document │ │ └── ReadmeParserTest.kt │ │ ├── dynamic │ │ ├── DynamicContextFactoryTest.kt │ │ ├── DynamicContextTest.kt │ │ └── functions │ │ │ └── IntroduceSystemFunctionTest.kt │ │ └── model │ │ ├── DomainModelScannerTest.kt │ │ └── UmlConverterTest.kt │ └── resources │ └── hello-world │ ├── README.md │ └── build.gradle.kts ├── comate-gui ├── .env.example ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── app │ ├── actions.ts │ ├── api │ │ ├── action │ │ │ └── tooling │ │ │ │ └── route.ts │ │ ├── auth │ │ │ └── [...nextauth] │ │ │ │ └── route.ts │ │ ├── chat │ │ │ ├── route.ts │ │ │ └── stream.ts │ │ └── common │ │ │ └── search-tooling.ts │ ├── chat │ │ └── [id] │ │ │ └── page.tsx │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── assets │ └── fonts │ │ ├── Inter-Bold.woff │ │ └── Inter-Regular.woff ├── auth.ts ├── components │ ├── button-scroll-to-bottom.tsx │ ├── chat-list.tsx │ ├── chat-message-actions.tsx │ ├── chat-message.tsx │ ├── chat-panel.tsx │ ├── chat-scroll-anchor.tsx │ ├── chat.tsx │ ├── clear-history.tsx │ ├── empty-screen.tsx │ ├── external-link.tsx │ ├── footer.tsx │ ├── header.tsx │ ├── login-button.tsx │ ├── markdown.tsx │ ├── prompt-form.tsx │ ├── providers.tsx │ ├── render │ │ ├── action-button.tsx │ │ ├── markdown-render.tsx │ │ └── message-render.tsx │ ├── sidebar-actions.tsx │ ├── sidebar-footer.tsx │ ├── sidebar-item.tsx │ ├── sidebar-list.tsx │ ├── sidebar.tsx │ ├── tailwind-indicator.tsx │ ├── theme-toggle.tsx │ ├── toaster.tsx │ ├── ui │ │ ├── alert-dialog.tsx │ │ ├── badge.tsx │ │ ├── button.tsx │ │ ├── codeblock.tsx │ │ ├── dialog.tsx │ │ ├── dropdown-menu.tsx │ │ ├── icons.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ ├── select.tsx │ │ ├── separator.tsx │ │ ├── sheet.tsx │ │ ├── switch.tsx │ │ ├── textarea.tsx │ │ └── tooltip.tsx │ └── user-menu.tsx ├── lib │ ├── fonts.ts │ ├── hooks │ │ ├── use-at-bottom.tsx │ │ ├── use-copy-to-clipboard.tsx │ │ ├── use-enter-submit.tsx │ │ └── use-local-storage.ts │ ├── types.ts │ └── utils.ts ├── middleware.ts ├── next-auth.d.ts ├── next-env.d.ts ├── next.config.js ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── prettier.config.cjs ├── public │ ├── apple-touch-icon.png │ ├── co-mate.svg │ ├── favicon-16x16.png │ └── favicon.ico ├── tailwind.config.js └── tsconfig.json ├── comate-server ├── .gitignore ├── build.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── comate │ │ │ └── server │ │ │ ├── Application.kt │ │ │ ├── action │ │ │ ├── ComateActionController.kt │ │ │ ├── ComateToolingAction.kt │ │ │ └── dto │ │ │ │ ├── ActionResult.kt │ │ │ │ └── ToolingThought.kt │ │ │ ├── lang │ │ │ └── LangController.kt │ │ │ └── prompt │ │ │ ├── PromptController.kt │ │ │ ├── PromptingWrapper.kt │ │ │ ├── dto │ │ │ ├── PromptToolingReq.kt │ │ │ └── PromptToolingRes.kt │ │ │ └── model │ │ │ └── BaseTool.kt │ └── resources │ │ ├── application.conf │ │ └── logback.xml │ └── test │ └── kotlin │ └── org │ └── archguard │ └── comate │ └── server │ ├── ApplicationKtTest.kt │ ├── PromptingWrapperTest.kt │ ├── action │ ├── ComateActionControllerKtTest.kt │ ├── ComateToolingActionTest.kt │ └── GovernanceDslTest.kt │ └── prompt │ └── PromptControllerKtTest.kt ├── docs ├── 7-layer-openbanking.puml ├── 7-levels.puml ├── README.md ├── adr │ ├── 0001-use-compose-for-gui.md │ ├── 0002-neighbor-architecture-generative-framework.md │ ├── 0003-separate-implmentation-&-design-architecture.md │ ├── 0004-enterprise-architecture-less-in-co-mate.md │ └── README.md ├── co-mate.svg ├── compose.md ├── debug │ ├── backend-prompt.md │ └── ui-debug.md ├── docs.md ├── dynamic-context.md ├── examples │ └── cafe-delivery.md ├── governance │ ├── BACKEND-BASIC.md │ ├── README.md │ └── RESTful-API-Design-Specification.md ├── prompt │ ├── README.md │ └── autogpt.md ├── sample │ └── workflow+activity.md └── vocabulary │ ├── domain-vocabulary.csv │ └── rest-api.csv ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── legacy └── comate-gui │ ├── README.md │ ├── build.gradle.kts │ └── src │ └── jvmMain │ └── kotlin │ ├── Main.kt │ ├── component │ ├── MessageCard.kt │ ├── MessageList.kt │ └── TextInput.kt │ ├── model │ ├── ConversationModel.kt │ ├── ConversationViewModel.kt │ └── MessageModel.kt │ └── theme │ ├── Color.kt │ └── Theme.kt ├── llm-core ├── LICENSE ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── comate │ │ ├── connector │ │ ├── LlmConnector.kt │ │ └── OpenAIConnector.kt │ │ ├── governance │ │ └── ApiRuleVerifier.kt │ │ └── token │ │ ├── LlmTokenCalculate.kt │ │ └── TokenCalculate.kt │ └── test │ └── kotlin │ └── org │ └── archguard │ └── comate │ ├── connector │ └── OpenAIConnectorTest.kt │ └── token │ └── LlmTokenCalculateTest.kt ├── llm-semantic ├── build.gradle.kts └── src │ └── main │ ├── kotlin │ └── org │ │ └── archguard │ │ └── comate │ │ └── smart │ │ ├── CosineSimilarity.kt │ │ └── Semantic.kt │ └── resources │ └── model │ ├── LICENSE │ ├── model.onnx │ ├── special_tokens_map.json │ ├── tokenizer.json │ ├── tokenizer_config.json │ └── vocab.txt ├── settings.gradle.kts ├── spec-lang ├── README.md ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── org │ │ └── archguard │ │ └── spec │ │ ├── base │ │ ├── LlmRule.kt │ │ ├── Rule.kt │ │ ├── RuleResult.kt │ │ └── verifier │ │ │ └── LlmRuleVerifier.kt │ │ ├── element │ │ ├── Element.kt │ │ ├── FoundationElement.kt │ │ └── RestApiElement.kt │ │ ├── execute │ │ └── DomainModelScanner.kt │ │ └── lang │ │ ├── ArchitectureSpec.kt │ │ ├── CaseFlowSpec.kt │ │ ├── ComposableSpec.kt │ │ ├── ConceptSpec.kt │ │ ├── DomainSpec.kt │ │ ├── FoundationSpec.kt │ │ ├── RestApiSpec.kt │ │ ├── SpecDsl.kt │ │ ├── architecture │ │ └── ArchitectureDeclaration.kt │ │ ├── base │ │ ├── BaseDeclaration.kt │ │ ├── PatternWithExampleRule.kt │ │ └── Spec.kt │ │ ├── caseflow │ │ ├── CaseFlowModel.kt │ │ └── declaration │ │ │ ├── SceneDeclaration.kt │ │ │ └── StoryDeclaration.kt │ │ ├── concept │ │ ├── Behavior.kt │ │ ├── CodeBlock.kt │ │ └── declaration │ │ │ └── ConceptDeclaration.kt │ │ ├── domain │ │ ├── MappingDefine.kt │ │ └── declaration │ │ │ ├── AggregateDeclaration.kt │ │ │ ├── ContextDeclaration.kt │ │ │ └── ContextMapDeclaration.kt │ │ ├── foundation │ │ ├── declaration │ │ │ ├── LayeredDeclaration.kt │ │ │ ├── LayeredDefine.kt │ │ │ └── NamingDeclaration.kt │ │ ├── expression │ │ │ └── NamingRuleExpression.kt │ │ └── rule │ │ │ ├── DependencyRule.kt │ │ │ ├── NamingRule.kt │ │ │ ├── NamingStyleRule.kt │ │ │ └── ProjectNameRule.kt │ │ ├── matcher │ │ ├── Compare.kt │ │ └── Matcher.kt │ │ └── restapi │ │ ├── ApiAtomicRule.kt │ │ ├── ApiLlmVerifyRule.kt │ │ └── rule │ │ ├── HttpActionRule.kt │ │ ├── MiscRule.kt │ │ ├── SecurityRule.kt │ │ ├── StatusCodeRule.kt │ │ └── UriConstructionRule.kt │ └── test │ ├── kotlin │ └── org │ │ └── archguard │ │ ├── architecture │ │ └── action │ │ │ └── IOActionTypeTest.kt │ │ └── spec │ │ └── lang │ │ ├── ArchitectureSpecTest.kt │ │ ├── CaseFlowSpecTest.kt │ │ ├── ComposableSpecTest.kt │ │ ├── ConceptSpecTest.kt │ │ ├── DomainSpecTest.kt │ │ ├── FoundationSpecTest.kt │ │ ├── RestRestApiSpecTest.kt │ │ ├── foundation │ │ ├── declaration │ │ │ ├── LayeredDeclarationTest.kt │ │ │ ├── LayeredDefineTest.kt │ │ │ └── NamingDeclarationTest.kt │ │ └── rule │ │ │ ├── DependencyRuleTest.kt │ │ │ ├── NamingRuleTest.kt │ │ │ ├── NamingStyleRuleTest.kt │ │ │ └── ProjectNameRuleTest.kt │ │ └── matcher │ │ └── DelayCompareTest.kt │ └── resources │ └── spec │ └── ddd-mono-repo-demo.json ├── spec-partitioner ├── build.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── org │ │ │ └── archguard │ │ │ └── spec │ │ │ ├── markdown │ │ │ ├── CodeBlockFilter.kt │ │ │ ├── MarkdownParser.kt │ │ │ └── TableToMapVisitor.kt │ │ │ └── partition │ │ │ ├── ApiPartitioner.kt │ │ │ └── Partitioner.kt │ └── resources │ │ └── restful │ │ ├── status-code.txt │ │ └── uri-construction.txt │ └── test │ └── kotlin │ └── org │ └── archguard │ └── spec │ ├── ApiPartitionerTest.kt │ └── markdown │ └── MarkdownParserTest.kt └── spec-runtime ├── build.gradle.kts └── src ├── main └── kotlin │ └── org │ └── archguard │ └── spec │ └── runtime │ ├── KotlinInterpreter.kt │ ├── api │ └── InterpreterRequest.kt │ ├── compiler │ ├── CustomLibraryResolver.kt │ ├── ExtendLibraries.kt │ └── KotlinReplWrapper.kt │ └── messaging │ ├── Message.kt │ └── MessageType.kt └── test └── kotlin └── org └── archguard └── spec └── runtime ├── KotlinInterpreterTest.kt └── compiler └── KotlinReplWrapperTest.kt /.adr.json: -------------------------------------------------------------------------------- 1 | {"language":"en","path":"docs/adr/","prefix":"","digits":4} -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | model/vocab.txt filter=lfs diff=lfs merge=lfs -text 2 | model/model.onnx filter=lfs diff=lfs merge=lfs -text 3 | model/special_tokens_map.json filter=lfs diff=lfs merge=lfs -text 4 | model/tokenizer.json filter=lfs diff=lfs merge=lfs -text 5 | model/tokenizer_config.json filter=lfs diff=lfs merge=lfs -text 6 | # 7 | # https://help.github.com/articles/dealing-with-line-endings/ 8 | # 9 | # Linux start script should use lf 10 | /gradlew text eol=lf 11 | 12 | # These are Windows script files and should use crlf 13 | *.bat text eol=crlf 14 | 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Env (please complete the following information):** 14 | - OS: [e.g. iOS] 15 | - Env: Docker compose? Local dev? 16 | - Browser [e.g. chrome, safari] 17 | - Version [e.g. 22] 18 | 19 | 20 | **To Reproduce** 21 | Steps to reproduce the behavior: 22 | 1. Go to '...' 23 | 2. Click on '....' 24 | 3. Scroll down to '....' 25 | 4. See error 26 | 27 | **Expected behavior** 28 | A clear and concise description of what you expected to happen. 29 | 30 | **Screenshots** 31 | If applicable, add screenshots to help explain your problem. 32 | 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-framework-support.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New framework support 3 | about: new framework support 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Which language would you to support** 11 | xxx 12 | 13 | **Example of this language HTTP API syntax** 14 | xxx 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | name: CD 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | assets: 14 | - comate-cli/build/libs/comate-cli-*-all.jar 15 | - comate-server/build/libs/comate-server-all.jar 16 | 17 | permissions: 18 | contents: write 19 | packages: write 20 | steps: 21 | - uses: actions/checkout@v3 22 | - uses: actions/setup-java@v3 23 | with: 24 | distribution: 'zulu' 25 | java-version: '11' 26 | cache: 'gradle' 27 | 28 | - name: Setup Gradle 29 | run: ./gradlew build --no-daemon -x test 30 | 31 | - name: Upload assets to release 32 | uses: svenstaro/upload-release-action@v2 33 | with: 34 | repo_token: ${{ secrets.GITHUB_TOKEN }} 35 | file: ${{ matrix.assets }} 36 | tag: ${{ github.ref }} 37 | overwrite: true 38 | file_glob: true 39 | 40 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [ push ] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | matrix: 9 | os: [ macos-latest, ubuntu-latest, windows-latest ] 10 | runs-on: ${{ matrix.os }} 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | 15 | - name: Use Node.js 16.x 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: 16.x 19 | 20 | - uses: pnpm/action-setup@v2 21 | with: 22 | version: 6.0.2 23 | 24 | - name: build 25 | env: 26 | NODE_OPTIONS: --max_old_space_size=4096 27 | run: | 28 | cd comate-gui 29 | pnpm install 30 | pnpm build 31 | 32 | - uses: actions/setup-java@v3 33 | with: 34 | distribution: 'zulu' 35 | java-version: '11' 36 | cache: 'gradle' 37 | 38 | - name: Setup Gradle 39 | run: ./gradlew build --no-daemon -x test 40 | 41 | - name: Execute Gradle Coverage 42 | run: ./gradlew check 43 | 44 | - name: Coveralls 45 | uses: coverallsapp/github-action@v2 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | # Compiled class file 9 | *.class 10 | 11 | # Log file 12 | *.log 13 | 14 | # BlueJ files 15 | *.ctxt 16 | 17 | # Mobile Tools for Java (J2ME) 18 | .mtj.tmp/ 19 | 20 | # Package Files # 21 | *.jar 22 | *.war 23 | *.nar 24 | *.ear 25 | *.zip 26 | *.tar.gz 27 | *.rar 28 | 29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 30 | hs_err_pid* 31 | replay_pid* 32 | .idea 33 | # Ignore Gradle project-specific cache directory 34 | .gradle 35 | 36 | # Ignore Gradle build output directory 37 | build 38 | .env 39 | dependencies.json 40 | codedatastructs.json -------------------------------------------------------------------------------- /_fixtures/governance/api/untitled/src/main/java/cc/unitmesh/untitled/demo/controller/BlogController.java: -------------------------------------------------------------------------------- 1 | package cc.unitmesh.untitled.demo.controller; 2 | 3 | import cc.unitmesh.untitled.demo.service.BlogService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | 8 | @RestController 9 | @RequestMapping("/api") 10 | public class BlogController { 11 | BlogService blogService; 12 | 13 | public BlogController(BlogService blogService) { 14 | this.blogService = blogService; 15 | } 16 | 17 | @PostMapping("/blog/get") 18 | public String get() { 19 | return ""; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /agent/rust/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | instructions.jsonl -------------------------------------------------------------------------------- /agent/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "comate-agent" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MPL-2.0" 6 | readme = "README.md" 7 | repository = "https://github.com/archguard/comate" 8 | documentation = "https://github.com/archguard/comate" 9 | homepage = "https://github.com/archguard/comate" 10 | description = """ 11 | Co-mate is an AI-powered architecture copilot, design and governance tools. 12 | """ 13 | categories = ["text-processing", "command-line-interface", "development-tools"] 14 | exclude = [ 15 | ".github/*", 16 | ".gitattributes", 17 | ".adr.json", 18 | "guarding.guarding", 19 | "_fixtures", 20 | "docs", 21 | "examples", 22 | ] 23 | 24 | [[bin]] 25 | name = "agent" 26 | 27 | [dependencies] 28 | 29 | # embedding 30 | ort = "1.14.6" 31 | tokenizers = "0.13.3" 32 | ndarray = "0.15" 33 | 34 | # log 35 | log = "0.4.18" 36 | tracing = "0.1.37" 37 | tracing-subscriber = { version = "0.3.16", features = ["env-filter", "registry"] } 38 | 39 | # error handling 40 | anyhow = "1.0.68" 41 | thiserror = "1.0.38" 42 | 43 | # serde 44 | serde = "1.0.152" 45 | erased-serde = "0.3.25" 46 | serde_json = "1.0.91" 47 | 48 | # Cache 49 | uluru = "3.0.0" 50 | 51 | # RPC Server 52 | fern = "0.6.2" 53 | xi-rpc = "0.3.0" 54 | chrono = "0.4.24" 55 | dirs = "5.0.1" 56 | 57 | # Segmentation fault in time: https://github.com/archguard/co-mate/security/dependabot/2 58 | time = "=0.3.22" -------------------------------------------------------------------------------- /agent/rust/README.md: -------------------------------------------------------------------------------- 1 | # Comate Agent 2 | 3 | Ref to: [https://github.com/unit-mesh/unit-agent](https://github.com/unit-mesh/unit-agent) 4 | 5 | - Cache for Embedding Content 6 | - Embedding API for String 7 | - Relevant API for Embedding 8 | 9 | Command: 10 | 11 | - Notifications 12 | - Request 13 | - relevant-compute 14 | - embedding 15 | - llm prompt 16 | 17 | ## LICENSE 18 | 19 | This project is licensed under the MPL-2.0 License. See the [LICENSE](LICENSE) file for details 20 | -------------------------------------------------------------------------------- /agent/rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod rpc; -------------------------------------------------------------------------------- /agent/rust/src/rpc/client.rs: -------------------------------------------------------------------------------- 1 | use serde_json::json; 2 | use xi_rpc::RpcPeer; 3 | 4 | pub struct Client(pub(crate) RpcPeer); 5 | 6 | const VERSION: &str = env!("CARGO_PKG_VERSION"); 7 | 8 | impl Client { 9 | pub fn new(peer: RpcPeer) -> Self { 10 | Client(peer) 11 | } 12 | 13 | pub fn send_client_started(&self) { 14 | self.0.send_rpc_notification( 15 | "client_started", 16 | &json!({ 17 | "version": VERSION, 18 | }), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /agent/rust/src/rpc/mod.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Mutex, Weak}; 2 | 3 | use serde_json::{self, json, Value}; 4 | use xi_rpc::{RemoteError, RpcPeer}; 5 | 6 | use client::Client; 7 | use request::CoreRequest; 8 | 9 | mod notification; 10 | mod request; 11 | pub mod unit_rpc; 12 | mod client; 13 | 14 | #[allow(dead_code)] 15 | pub struct CoreState { 16 | peer: Client, 17 | token: Option, 18 | } 19 | 20 | impl CoreState { 21 | pub(crate) fn new(peer: &RpcPeer) -> Self { 22 | CoreState { 23 | peer: Client::new(peer.clone()), 24 | token: None, 25 | } 26 | } 27 | 28 | pub(crate) fn client_request(&mut self, cmd: CoreRequest) -> Result { 29 | use request::CoreRequest::*; 30 | match cmd { 31 | Config { open_ai_token, .. } => { 32 | self.token = Some(open_ai_token); 33 | Ok(json!({ 34 | "success": true 35 | })) 36 | } 37 | } 38 | } 39 | 40 | pub(crate) fn finish_setup(&mut self, _self_ref: WeakCoreState) { 41 | self.peer.send_client_started() 42 | } 43 | 44 | pub(crate) fn handle_idle(&mut self, token: usize) { 45 | match token { 46 | _ => { 47 | // info!("token: {}", token); 48 | } 49 | } 50 | } 51 | } 52 | 53 | /// A weak reference to the main state. This is passed to plugin threads. 54 | #[derive(Clone)] 55 | pub struct WeakCoreState(Weak>); 56 | -------------------------------------------------------------------------------- /agent/rust/src/rpc/notification.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::path::PathBuf; 3 | 4 | #[derive(Serialize, Deserialize, Debug, PartialEq)] 5 | #[serde(rename_all = "snake_case")] 6 | #[serde(tag = "method", content = "params")] 7 | pub enum CoreNotification { 8 | WorkspaceFileOpened { 9 | uri: String, 10 | language_id: String, 11 | text: String, 12 | }, 13 | WorkspaceFileClosed { 14 | uri: String, 15 | }, 16 | WorkspaceFileChanged { 17 | uri: String, 18 | text: String, 19 | }, 20 | Initialize { 21 | #[serde(default)] 22 | config_dir: Option, 23 | }, 24 | Shutdown, 25 | } 26 | -------------------------------------------------------------------------------- /agent/rust/src/rpc/request.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Serialize, Deserialize, Debug, PartialEq)] 4 | #[serde(rename_all = "snake_case")] 5 | #[serde(tag = "method", content = "params")] 6 | pub enum CoreRequest { 7 | Config { 8 | open_ai_token: String, 9 | open_ai_url: Option, 10 | }, 11 | } 12 | 13 | #[derive(Serialize, Deserialize, Debug, PartialEq)] 14 | #[serde(rename_all = "camelCase")] 15 | pub struct Document { 16 | position: Position, 17 | use_spaces: bool, 18 | tab_size: u32, 19 | uri: String, 20 | version: u32, 21 | } 22 | 23 | #[derive(Serialize, Deserialize, Debug, PartialEq)] 24 | #[serde(rename_all = "snake_case")] 25 | pub struct Position { 26 | line: u32, 27 | character: u32, 28 | } 29 | -------------------------------------------------------------------------------- /architecture/README.md: -------------------------------------------------------------------------------- 1 | # 架构分析 2 | 3 | Refs: 4 | 5 | - [Architecture Description Language (ADL)](https://cio-wiki.org/wiki/Architecture_Description_Language_(ADL)) 6 | 7 | ## 通过领域生成架构特征 8 | 9 | 1. 如何识别领域知识? 10 | 11 | ## 多个子系统导入 12 | 13 | 基于 CSV, JSON, Markdown 14 | 15 | ## 基于依赖的框架映射,分析出架构分格 16 | 17 | Maven Index: [https://maven.apache.org/repository/central-index.html](https://maven.apache.org/repository/central-index.html) 18 | 19 | 示例: 20 | 21 | 1. Spring Boot => 微服务架构 22 | 2. Equinox => OSGI 23 | 3. Flink, Kafka => Data => ServiceBased 24 | 25 | ## Arch 26 | 27 | ```yaml 28 | # 分析态输出 29 | - langauge: java 30 | conceptualArch: 31 | domains: [ "" ] 32 | styles: 33 | layeredStyle: [""] 34 | moduleArch: 35 | systems: [ "" ] 36 | subSystems: [ "" ] 37 | # from Gradle or maven 38 | modules: [ "" ] 39 | layers: [ "" ] 40 | interfaces: [ "" ] 41 | changeImpact: [ "" ] 42 | executionArch: 43 | # Interface description language 44 | interfaceDescriptionLanguage: [ "proto" ] 45 | messageQueue: [ "RabbitMQ", "Kafka" ] 46 | # hasProcesses 47 | processes: [ "ProcessBuilder" ] 48 | # thread 49 | # kotlin.concurrent.thread 50 | servers: [ "" ] 51 | codeArch: 52 | # from CLOC 53 | languages: [ "" ] 54 | # packageManager 55 | developmentTools: [ "" ] 56 | libraries: [ "" ] 57 | packages: [ "" ] 58 | directories: [ "" ] 59 | files: [ "" ] 60 | ``` 61 | 62 | ## 案例库 63 | 64 | ```yaml 65 | # Domain 66 | - domain: GUI 67 | characteristics: 68 | - WindowManager 69 | - domain: finance 70 | characteristics: 71 | - 并发 72 | ``` -------------------------------------------------------------------------------- /architecture/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @Suppress("DSL_SCOPE_VIOLATION") 2 | 3 | plugins { 4 | alias(libs.plugins.jvm) 5 | alias(libs.plugins.serialization) 6 | } 7 | 8 | dependencies { 9 | implementation(libs.chapi.domain) 10 | 11 | implementation(libs.kotlin.reflect) 12 | implementation(libs.serialization.json) 13 | 14 | testImplementation(libs.bundles.test) 15 | } 16 | -------------------------------------------------------------------------------- /architecture/src/main/kotlin/org/archguard/architecture/action/IOAction.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.action 2 | 3 | interface IOAction { 4 | fun execute() 5 | } 6 | 7 | class EmptyIOAction(): IOAction { 8 | override fun execute() { 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /architecture/src/main/kotlin/org/archguard/architecture/action/IOActionType.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.action 2 | 3 | enum class IOActionType(val actionName: String) { 4 | CREATE_DIRECTORY("create_directory") { 5 | override fun createAction(args: List): IOAction { 6 | return EmptyIOAction() 7 | } 8 | }, 9 | CREATE_FILE("create_file") { 10 | override fun createAction(args: List): IOAction { 11 | return EmptyIOAction() 12 | } 13 | }, 14 | 15 | CREATE_PACKAGE("create_package") { 16 | override fun createAction(args: List): IOAction { 17 | return EmptyIOAction() 18 | } 19 | }, 20 | CREATE_CLASS("create_class") { 21 | override fun createAction(args: List): IOAction { 22 | return EmptyIOAction() 23 | } 24 | }, 25 | CREATE_INTERFACE("create_interface") { 26 | override fun createAction(args: List): IOAction { 27 | return EmptyIOAction() 28 | } 29 | }, 30 | CREATE_ENUM("create_enum") { 31 | override fun createAction(args: List): IOAction { 32 | return EmptyIOAction() 33 | } 34 | }, 35 | UNKNOWN("unknown") { 36 | override fun createAction(args: List): IOAction { 37 | return EmptyIOAction() 38 | } 39 | } 40 | ; 41 | 42 | abstract fun createAction(args: List): IOAction 43 | 44 | companion object { 45 | fun from(source: String): IOActionType { 46 | return values().find { it.actionName == source.lowercase() } ?: UNKNOWN 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /architecture/src/main/kotlin/org/archguard/architecture/action/RefactoringAction.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.action 2 | 3 | interface RefactoringAction { 4 | fun execute() 5 | } 6 | 7 | /** 8 | * Refactoring to design-pattern's type 9 | */ 10 | enum class RefactoringToPatternType(val displayName: String) { 11 | 12 | } -------------------------------------------------------------------------------- /architecture/src/main/kotlin/org/archguard/architecture/layered/ArchitectureStyle.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.layered 2 | 3 | enum class ArchitectureStyle(val value: String) { 4 | LAYERED("layered"), 5 | PIPELINE("pipeline"), 6 | MICROKERNEL("microkernel"), 7 | SERVICEBASED("servicebased"), 8 | SERVERLESS("serverless"), 9 | EVENTDRIVEN("eventdriven"), 10 | SPACEBASED("spacebased"), 11 | MICROSERVICE("microservice"), 12 | UNKNOWN("unknown") 13 | ; 14 | 15 | companion object { 16 | fun contains(string: String): Boolean { 17 | val lowercase = string.lowercase() 18 | return values().any { it.value == lowercase } 19 | } 20 | 21 | fun from(string: String): ArchitectureStyle { 22 | val lowercase = string.lowercase() 23 | return values().find { it.value == lowercase } ?: UNKNOWN 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /architecture/src/main/kotlin/org/archguard/architecture/layered/Channel.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.layered 2 | 3 | enum class ChannelType(val displayName: String) { 4 | WEBSITE("Website"), 5 | MOBILE_APP("Mobile App"), 6 | PHONE("Phone"), 7 | EMAIL("Email"), 8 | SOCIAL_MEDIA("Social Media"), 9 | ONLINE_CHAT("Online Chat"), 10 | IN_PERSON_STORE("In-person Store"), 11 | SELF_SERVICE_KIOSK("Self-service Kiosk"), 12 | VOICE_ASSISTANT("Voice Assistant"), 13 | VIDEO_CONFERENCING("Video Conferencing"), 14 | SMS("SMS"), 15 | FAX("Fax"), 16 | MAIL("Mail"), 17 | INTERACTIVE_VOICE_RESPONSE("Interactive Voice Response"), 18 | VIRTUAL_REALITY("Virtual Reality"), 19 | AUGMENTED_REALITY("Augmented Reality"); 20 | 21 | companion object { 22 | fun allValues(): List { 23 | return values().map { it.displayName } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /architecture/src/main/kotlin/org/archguard/architecture/layered/LayeredStyle.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.layered 2 | 3 | enum class LayeredStyle(val value: String) { 4 | MVC("mvc"), 5 | MVP("mvp"), 6 | MVVM("mvvm"), 7 | VIPER("viper"), 8 | CLEAN("clean"), 9 | DDD("ddd"), 10 | ONION("onion"), 11 | HEXAGONAL("hexagonal") 12 | ; 13 | 14 | companion object { 15 | fun contains(string: String): Boolean { 16 | val lowercase = string.lowercase() 17 | return values().any { it.value == lowercase } 18 | } 19 | 20 | fun valuesString(): String { 21 | return values().joinToString(", ") { it.value } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /architecture/src/main/kotlin/org/archguard/architecture/style/NameStyle.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.style 2 | 3 | import java.util.* 4 | 5 | enum class NamingStyle(val value: String) { 6 | UpperCamelCase("UpperCamelCase") { 7 | override fun isValid(string: String): Boolean { 8 | return string.matches(Regex("[A-Z][a-zA-Z0-9]+")) 9 | } 10 | }, 11 | CamelCase("CamelCase") { 12 | override fun isValid(string: String): Boolean { 13 | return string.matches(Regex("[a-zA-Z]+([A-Za-z0-9]+)*")) 14 | } 15 | }, 16 | SnakeCase("SnakeCase") { 17 | override fun isValid(string: String): Boolean { 18 | return string.matches(Regex("[a-z]+(_[a-z0-9]+)*")) 19 | } 20 | }, 21 | KebabCase("KebabCase") { 22 | override fun isValid(string: String): Boolean { 23 | return string.matches(Regex("[a-z]+(-[a-z0-9]+)*")) 24 | } 25 | } 26 | ; 27 | 28 | companion object { 29 | fun contains(string: String): Boolean { 30 | val lowercase = string.lowercase() 31 | return NamingStyle.values().any { it.value.lowercase() == lowercase } 32 | } 33 | 34 | fun valuesString(): String { 35 | return NamingStyle.values().joinToString(", ") { it.value } 36 | } 37 | 38 | fun toSnakeCase(string: String): String { 39 | return string.replace(Regex("([a-z])([A-Z]+)"), "$1_$2").lowercase(Locale.getDefault()) 40 | } 41 | } 42 | 43 | abstract fun isValid(string: String): Boolean 44 | } -------------------------------------------------------------------------------- /architecture/src/test/kotlin/org/archguard/architecture/layered/ArchitectureStyleTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.layered 2 | 3 | import org.junit.jupiter.api.Assertions.* 4 | import org.junit.jupiter.api.Test 5 | 6 | class ArchitectureStyleTest { 7 | @Test 8 | fun should_get_class_by_value_of() { 9 | assertEquals(ArchitectureStyle.LAYERED, ArchitectureStyle.from("LAYERED")) 10 | assertEquals(ArchitectureStyle.PIPELINE, ArchitectureStyle.from("PIPELINE")) 11 | 12 | assertEquals(ArchitectureStyle.UNKNOWN, ArchitectureStyle.from("NOT_EXIST")) 13 | } 14 | 15 | @Test 16 | fun should_return_true_when_has_contains() { 17 | assertTrue(ArchitectureStyle.contains("layered")) 18 | assertTrue(ArchitectureStyle.contains("PIPELINE")) 19 | } 20 | } -------------------------------------------------------------------------------- /architecture/src/test/kotlin/org/archguard/architecture/layered/ChannelTypeTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.layered 2 | 3 | import io.kotest.matchers.shouldBe 4 | import org.junit.jupiter.api.Test 5 | 6 | class ChannelTypeTest { 7 | @Test 8 | fun test_all_values() { 9 | ChannelType.values().size shouldBe 16 10 | ChannelType.values().first().displayName shouldBe "Website" 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /architecture/src/test/kotlin/org/archguard/architecture/style/NamingStyleTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.architecture.style 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | 6 | class NamingStyleTest { 7 | @Test 8 | fun should_convert_to_snake_case() { 9 | val name = NamingStyle.toSnakeCase("HelloWorld") 10 | assertEquals("hello_world", name) 11 | 12 | // three words 13 | val name2 = NamingStyle.toSnakeCase("HelloWorldAgain") 14 | assertEquals("hello_world_again", name2) 15 | } 16 | 17 | @Test 18 | fun should_verify_naming_style() { 19 | val name = "HelloWorld" 20 | assertEquals(true, NamingStyle.UpperCamelCase.isValid(name)) 21 | assertEquals(true, NamingStyle.CamelCase.isValid(name)) 22 | assertEquals(false, NamingStyle.SnakeCase.isValid(name)) 23 | assertEquals(false, NamingStyle.KebabCase.isValid(name)) 24 | 25 | val name2 = "helloWorld" 26 | assertEquals(false, NamingStyle.UpperCamelCase.isValid(name2)) 27 | assertEquals(true, NamingStyle.CamelCase.isValid(name2)) 28 | assertEquals(false, NamingStyle.SnakeCase.isValid(name2)) 29 | assertEquals(false, NamingStyle.KebabCase.isValid(name2)) 30 | 31 | val name3 = "hello_world" 32 | assertEquals(false, NamingStyle.UpperCamelCase.isValid(name3)) 33 | assertEquals(false, NamingStyle.CamelCase.isValid(name3)) 34 | assertEquals(true, NamingStyle.SnakeCase.isValid(name3)) 35 | assertEquals(false, NamingStyle.KebabCase.isValid(name3)) 36 | 37 | val name4 = "hello-world" 38 | assertEquals(false, NamingStyle.UpperCamelCase.isValid(name4)) 39 | assertEquals(false, NamingStyle.CamelCase.isValid(name4)) 40 | assertEquals(false, NamingStyle.SnakeCase.isValid(name4)) 41 | assertEquals(true, NamingStyle.KebabCase.isValid(name4)) 42 | } 43 | } -------------------------------------------------------------------------------- /architecture/src/test/resources/testdata/spring-hello-world/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /architecture/src/test/resources/testdata/spring-hello-world/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("org.springframework.boot") version "2.7.13-SNAPSHOT" 4 | id("io.spring.dependency-management") version "1.0.15.RELEASE" 5 | } 6 | 7 | group = "com.example" 8 | version = "0.0.1-SNAPSHOT" 9 | java.sourceCompatibility = JavaVersion.VERSION_17 10 | 11 | configurations { 12 | compileOnly { 13 | extendsFrom(configurations.annotationProcessor.get()) 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url = uri("https://repo.spring.io/milestone") } 20 | maven { url = uri("https://repo.spring.io/snapshot") } 21 | } 22 | 23 | dependencies { 24 | implementation("org.springframework.boot:spring-boot-starter-data-rest") 25 | implementation("org.springframework.boot:spring-boot-starter-web") 26 | compileOnly("org.projectlombok:lombok") 27 | developmentOnly("org.springframework.boot:spring-boot-devtools") 28 | annotationProcessor("org.projectlombok:lombok") 29 | testImplementation("org.springframework.boot:spring-boot-starter-test") 30 | } 31 | 32 | tasks.withType { 33 | useJUnitPlatform() 34 | } 35 | -------------------------------------------------------------------------------- /architecture/src/test/resources/testdata/spring-hello-world/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url = uri("https://repo.spring.io/milestone") } 4 | maven { url = uri("https://repo.spring.io/snapshot") } 5 | gradlePluginPortal() 6 | } 7 | } 8 | rootProject.name = "demo" 9 | -------------------------------------------------------------------------------- /architecture/src/test/resources/testdata/spring-hello-world/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DemoApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /architecture/src/test/resources/testdata/spring-hello-world/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /architecture/src/test/resources/testdata/spring-hello-world/src/test/java/com/example/demo/DemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DemoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /comate-cli/README.md: -------------------------------------------------------------------------------- 1 | # Kotlin ML 2 | 3 | - JDL -> Java Deep Learning 4 | - KotlinDL -> Kotlin Deep Learning 5 | - Algorithmia 6 | - [ ] cosine similarits: https://huggingface.co/tasks/sentence-similarity 7 | 8 | ```kotlin 9 | val model = OnnxInferenceModel("element/element.onnx") 10 | val detections = model.inferAndCloseUsing(ExecutionProvider.CPU()) { 11 | // 12 | } 13 | ``` 14 | 15 | NDARRAY 16 | 17 | ```kotlin 18 | 19 | val manager = NDManager.newBaseManager() 20 | val inputIdsArray = manager.create(inputIds) 21 | val attentionMaskArray = manager.create(attentionMask) 22 | val tokenTypeIdsArray = manager.create(typeIds) 23 | 24 | ``` 25 | -------------------------------------------------------------------------------- /comate-cli/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @Suppress("DSL_SCOPE_VIOLATION") 2 | plugins { 3 | application 4 | alias(libs.plugins.jvm) 5 | alias(libs.plugins.serialization) 6 | alias(libs.plugins.shadow) 7 | } 8 | 9 | dependencies { 10 | implementation(projects.llmCore) 11 | implementation(projects.llmSemantic) 12 | implementation(projects.comateCore) 13 | implementation(projects.architecture) 14 | implementation(projects.specLang) 15 | 16 | implementation(projects.specRuntime) 17 | 18 | implementation(libs.dotenv) 19 | implementation(libs.bundles.openai) 20 | implementation(libs.bundles.markdown) 21 | 22 | implementation(libs.slf4j.simple) 23 | 24 | implementation(libs.kotlin.stdlib) 25 | implementation(libs.langtorch) 26 | 27 | testImplementation(libs.bundles.test) 28 | testRuntimeOnly(libs.test.junit.engine) 29 | } 30 | 31 | application { 32 | mainClass.set("org.archguard.comate.cli.MainKt") 33 | } 34 | 35 | tasks { 36 | shadowJar { 37 | manifest { 38 | attributes(Pair("Main-Class", "org.archguard.comate.cli.MainKt")) 39 | } 40 | // minimize() 41 | dependencies { 42 | exclude(dependency("org.junit.jupiter:.*:.*")) 43 | exclude(dependency("org.junit:.*:.*")) 44 | exclude(dependency("junit:.*:.*")) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /comate-cli/src/main/kotlin/org/archguard/comate/command/CommandEmbedMap.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.command 2 | 3 | import org.archguard.comate.smart.Semantic 4 | 5 | // todo: maybe we can built local function calling embedding map 6 | fun createFunctionCallingEmbedding(semantic: Semantic): Map> { 7 | val basicIntroCommand = listOf( 8 | "introduction system", 9 | "介绍一下这个系统", 10 | "介绍这个系统", 11 | "介绍系统", 12 | ) 13 | val archStyleCommand = listOf( 14 | "layered style", 15 | "what is layered style", 16 | "分析该系统的分层", 17 | ) 18 | val apiGovernanceCommand = listOf( 19 | "api governance", 20 | "治理 API ", 21 | "检查 API 规范", 22 | ) 23 | val apiGenCommand = listOf( 24 | "api generate", 25 | "生成 API", 26 | ) 27 | 28 | val foundationGovernanceCommand = listOf( 29 | "检查基础规范情况" 30 | ) 31 | 32 | return mapOf( 33 | ComateCommand.Intro to basicIntroCommand.map { semantic.embed(it) }, 34 | ComateCommand.LayeredStyle to archStyleCommand.map { semantic.embed(it) }, 35 | ComateCommand.ApiGovernance to apiGovernanceCommand.map { semantic.embed(it) }, 36 | ComateCommand.ApiGen to apiGenCommand.map { semantic.embed(it) }, 37 | ComateCommand.FoundationGovernance to foundationGovernanceCommand.map { semantic.embed(it) }, 38 | ) 39 | } -------------------------------------------------------------------------------- /comate-cli/src/test/kotlin/org/archguard/comate/command/ComateCommandTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.command 2 | 3 | import org.junit.jupiter.api.Assertions.* 4 | 5 | class ComateCommandTest { 6 | @org.junit.jupiter.api.Test 7 | fun fromText() { 8 | val cmd = "introduction system" 9 | val comateCommand = ComateCommand.fromText(cmd) 10 | assertEquals(ComateCommand.Intro, comateCommand) 11 | } 12 | } -------------------------------------------------------------------------------- /comate-core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @Suppress("DSL_SCOPE_VIOLATION") 2 | plugins { 3 | alias(libs.plugins.jvm) 4 | alias(libs.plugins.serialization) 5 | } 6 | 7 | dependencies { 8 | implementation(libs.kotlin.stdlib) 9 | 10 | implementation(projects.architecture) 11 | implementation(projects.llmCore) 12 | implementation(projects.specLang) 13 | implementation(projects.specRuntime) 14 | 15 | implementation(libs.bundles.openai) 16 | implementation(libs.bundles.markdown) 17 | 18 | implementation(libs.archguard.analyser.sca) 19 | 20 | implementation(libs.archguard.lang.kotlin) 21 | implementation(libs.archguard.lang.java) 22 | implementation(libs.archguard.lang.typescript) 23 | implementation(libs.archguard.lang.golang) 24 | implementation(libs.archguard.lang.python) 25 | implementation(libs.archguard.feat.apicalls) 26 | implementation(libs.chapi.domain) 27 | 28 | 29 | // format results to CSV format 30 | implementation("app.softwork:kotlinx-serialization-csv:0.0.13") 31 | implementation("app.softwork:kotlinx-serialization-flf:0.0.13") 32 | 33 | 34 | compileOnly("org.archguard.codedb:action-toolkit:0.1.2") 35 | implementation("org.archguard.codedb:checkout:0.1.2") 36 | 37 | implementation(libs.kotlin.reflect) 38 | implementation(libs.reflections) 39 | 40 | implementation(libs.plantuml) 41 | 42 | implementation(libs.slf4j.simple) 43 | 44 | implementation(libs.bundles.markdown) 45 | implementation(projects.specRuntime) 46 | 47 | testImplementation(libs.bundles.test) 48 | testRuntimeOnly(libs.test.junit.engine) 49 | } 50 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/action/ApiGenPrompter.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.strategy.CodePromptStrategy 5 | import org.archguard.comate.strategy.Strategy 6 | 7 | class ApiGenPrompter( 8 | val context: ComateContext, 9 | override val strategy: Strategy, 10 | ) : CodePromptStrategy { 11 | 12 | } -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/action/DesignSystemPrompter.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.strategy.CodePromptStrategy 5 | import org.archguard.comate.strategy.Strategy 6 | import org.archguard.spec.lang.CaseFlowSpec 7 | 8 | class DesignSystemPrompter( 9 | val context: ComateContext, 10 | override val strategy: Strategy, 11 | ) : CodePromptStrategy { 12 | override fun getRole(): String = "Architecture" 13 | override fun getInstruction(): String = "根据详细分析如下的需求信息,设计完整的端到端需求用例。" 14 | override fun getRequirements(): String = """ 15 | 1. 请按如下的 DSL 格式返回,不做解释。 16 | 17 | """.trimIndent() 18 | 19 | override fun getExtendData(): String { 20 | val dsl = CaseFlowSpec("", "").example() 21 | return """ 22 | 需求信息 如下: 23 | 24 | ### 25 | ${context.extArgs["actionInput"]} 26 | ### 27 | 28 | 29 | DSL 格式如下: 30 | ```kotlin 31 | $dsl 32 | ``` 33 | 34 | """.trimIndent() 35 | } 36 | } -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/action/FoundationGovernancePrompter.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.governance.ApiRuleVerifier 5 | import org.archguard.comate.strategy.CodePromptStrategy 6 | import org.archguard.comate.strategy.Strategy 7 | import org.archguard.spec.element.FoundationElement 8 | import org.archguard.spec.lang.FoundationSpec 9 | 10 | class FoundationGovernancePrompter( 11 | val context: ComateContext, 12 | override val strategy: Strategy, 13 | ) : CodePromptStrategy { 14 | override fun getRole(): String = "Architecture" 15 | override fun getInstruction(): String = "根据下面的信息,总结项目的基础规范实施情况。" 16 | override fun getRequirements(): String = """ 17 | 1. 使用业务场景的语言描述,不要使用技术术语。 18 | 2. 如果 result 是 true,请不要返回任何信息。 19 | 3. 如果 result 是 false,请返回不通过的原因,并根据 rule 提供符合规范的 API。 20 | 4. 你只返回如下的结果类似于: 21 | 22 | ### 23 | - `{xxx}` 不符合 { rule name } 规范,Rule: { rule },建议修改为 {new api}。 24 | ### 25 | """.trimIndent() 26 | 27 | override fun getExtendData(): String { 28 | val codeDataStructs = context.fetchDs() 29 | 30 | val governance = if (context.spec != null && context.spec!!.javaClass == FoundationSpec::class.java) { 31 | context.spec as FoundationSpec 32 | } else { 33 | FoundationSpec.defaultSpec() 34 | } 35 | 36 | governance.setVerifier(ApiRuleVerifier(context.connector!!)) 37 | val ruleResults = governance.exec(FoundationElement(context.projectName, codeDataStructs)) 38 | 39 | val failedResults = ruleResults.filter { !it.success } 40 | 41 | val introduction = context.fetchReadmeIntroduction() 42 | return """$introduction 43 | 44 | failed spec results: $failedResults 45 | 46 | """.trimIndent() 47 | } 48 | } -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/action/IntroductionCodePrompt.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action 2 | 3 | import org.archguard.architecture.layered.ChannelType 4 | import org.archguard.comate.code.dependencyMapping 5 | import org.archguard.comate.command.ComateContext 6 | import org.archguard.comate.strategy.CodePromptStrategy 7 | import org.archguard.comate.strategy.Strategy 8 | import org.archguard.scanner.core.sca.CompositionDependency 9 | 10 | class IntroductionCodePrompt( 11 | val context: ComateContext, 12 | override val strategy: Strategy, 13 | ) : CodePromptStrategy { 14 | override fun getRole(): String = "Architecture" 15 | override fun getInstruction(): String = "根据分析如下的 dependencies 等信息,分析并编写这个项目的介绍。" 16 | override fun getRequirements(): String = """1. 从 {all channel types} 中选择最可能的 {channel type},不做解释。 17 | 2. 根据 dependencies 分析这个应用的核心场景。 18 | 3. 根据 dependencies 分析这个应用要考虑的功能需求和非功能需求。 19 | 4. 你返回的介绍类似于:""" 20 | 21 | override fun getSample(): String { 22 | return """ 23 | ``` 24 | {xxx} 项目是一个 {channel type} 应用程序,使用了 {xxx} 和一系列相关的库来构建 {xxx} 等功能(介绍核心的框架)。 25 | 该应用还使用了一些第三方库来构建 {xxx} (诸如于用户界面),以及进行 {xxx} 等任务(诸如于任务调度等功能)。该应用需要考虑 {xxx} 等非功能需求。 26 | ```""".trimIndent() 27 | } 28 | 29 | override fun getExtendData(): String { 30 | val dep = context.fetchProjectDependencies() 31 | val depMap: Map> = CompositionDependency.dependencyMapping(dep, context.workdir) 32 | 33 | val instr = context.fetchReadmeIntroduction() 34 | 35 | val items = depMap.map { "| ${it.key} | ${it.value.joinToString(", ")} |" }.joinToString("\n") 36 | val channels = ChannelType.allValues() 37 | 38 | return instr + """ 39 | all channel types: $channels 40 | 41 | dependencies: 42 | 43 | | path | deps | 44 | | --- | --- | 45 | $items 46 | """ 47 | } 48 | } -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/action/LayeredStylePrompt.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.strategy.CodePromptStrategy 5 | import org.archguard.comate.strategy.Strategy 6 | 7 | class LayeredStylePrompt( 8 | val context: ComateContext, 9 | override val strategy: Strategy, 10 | ) : CodePromptStrategy { 11 | override fun getRole(): String = "Software Architecture" 12 | override fun getInstruction(): String = 13 | "根据下面的信息,分析项目的分层是否符合业内的通用规范?并绘制 Graphviz 图来表示。" 14 | 15 | override fun getRequirements(): String = """ 16 | 1. 如果存在相互引用,请用红线展示出来。 17 | 2. 只展示重要的分层,不要展示过多的细节。 18 | 4. 结合分层、subgraph 的方式来表示分层。 19 | 4. 示例如下: 20 | 21 | ```dot 22 | digraph G { 23 | rankdir=TB; 24 | node [shape=record, fontname=Helvetica]; 25 | edge [color=black, penwidth=1.0]; 26 | subgraph cluster_{} { 27 | label="{} Layer" 28 | } 29 | ``` 30 | """ 31 | 32 | override fun getExtendData(): String { 33 | val introduction = context.fetchReadmeIntroduction() 34 | return """$introduction 35 | 36 | package fan in: ${context.fetchPackageDependencies()} 37 | """ 38 | .trimIndent() 39 | 40 | } 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/action/base/BaseTemplate.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action.base 2 | 3 | interface BaseTemplate { 4 | fun getRole(): String = "" 5 | fun getInstruction(): String = "" 6 | fun getRequirements(): String = "" 7 | fun getSample(): String = "" 8 | fun getExtendData(): String = "" 9 | } 10 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/action/model/ApiResult.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action.model 2 | 3 | import kotlinx.serialization.Serializable 4 | import org.archguard.spec.base.RuleResult 5 | 6 | @Serializable 7 | data class ApiResult(val apiUri: String, val result: List) -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/code/CodeDataStructExt.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.code 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | 5 | fun CodeDataStruct.Companion.generatePackageDependencies(codeDataStructs: List): Map> { 6 | val packageList = codeDataStructs.map { it.Package }.distinct() 7 | val packageInOut = mutableMapOf>() 8 | 9 | codeDataStructs.forEach { 10 | val packageIn = it.Package 11 | if (packageIn.isEmpty()) return@forEach 12 | 13 | packageInOut[packageIn] = packageInOut[packageIn].orEmpty().toMutableList().apply { 14 | val elements = it.Imports.map { import -> import.Source } 15 | .map { source -> source.substringBeforeLast(".") } 16 | .filter { source -> packageList.contains(source) } 17 | 18 | elements.forEach { element -> 19 | if (!this.contains(element)) { 20 | this.add(element) 21 | } 22 | } 23 | } 24 | } 25 | 26 | return packageInOut.filter { it.value.isNotEmpty() } 27 | } 28 | 29 | fun CodeDataStruct.Companion.packageInString(codeDataStructs: List): String { 30 | val packageInOut = this.generatePackageDependencies(codeDataStructs) 31 | return """package fan in: $packageInOut""" 32 | } -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/code/ProjectDependency.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.code 2 | 3 | import org.archguard.scanner.core.sca.CompositionDependency 4 | import java.nio.file.Path 5 | import kotlin.io.path.Path 6 | import kotlin.io.path.relativeTo 7 | 8 | fun CompositionDependency.Companion.dependencyMapping( 9 | dep: List, 10 | workdir: Path, 11 | ): Map> { 12 | return dep.groupBy { 13 | val relativePath = Path(it.path).relativeTo(workdir).toString() 14 | relativePath 15 | }.mapValues { entry -> 16 | entry.value.map { it.depName } 17 | .toSet() 18 | .filter { it.isNotEmpty() && it != ":" } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/code/ServicesMap.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.code 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import org.archguard.scanner.analyser.ApiCallAnalyser 5 | import org.archguard.scanner.core.sourcecode.ContainerService 6 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 7 | import org.archguard.spec.element.RestApiElement 8 | 9 | class ServicesMap { 10 | companion object { 11 | fun scanApis( 12 | codeDataStructs: List?, 13 | codeContext: SourceCodeContext, 14 | ): List { 15 | val services: List = if (codeDataStructs != null) { 16 | ApiCallAnalyser(codeContext).analyse(codeDataStructs) 17 | } else { 18 | listOf() 19 | } 20 | 21 | val apis = services.flatMap { 22 | it.resources.map { resource -> 23 | RestApiElement( 24 | uri = resource.sourceUrl, 25 | httpAction = resource.sourceHttpMethod.uppercase(), 26 | statusCodes = listOf(200) 27 | ) 28 | } 29 | } 30 | return apis 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/document/IntroductionVisitor.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.document 2 | 3 | import org.commonmark.node.* 4 | 5 | class IntroductionVisitor : AbstractVisitor() { 6 | private var paragraphs = mutableListOf() 7 | private var headers = mutableListOf() 8 | 9 | override fun visit(paragraph: Paragraph?) { 10 | var result = "" 11 | if (paragraph?.firstChild is Text) { 12 | result += (paragraph.firstChild as Text).literal 13 | var next = paragraph.firstChild?.next 14 | 15 | while (next is Text || next is SoftLineBreak) { 16 | if (next is Text) { 17 | result += "\n" + next.literal 18 | } 19 | 20 | next = next.next 21 | } 22 | 23 | paragraphs.add(result) 24 | } 25 | } 26 | 27 | override fun visit(heading: Heading?) { 28 | if (heading?.firstChild is Text) { 29 | headers.add((heading.firstChild as Text).literal) 30 | } 31 | } 32 | 33 | fun introduction(): ReadmeIntroduction { 34 | val title = headers.firstOrNull() ?: "" 35 | val description = paragraphs.firstOrNull() ?: "" 36 | 37 | return ReadmeIntroduction(title, description) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/document/ReadmeParser.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.document 2 | 3 | import org.commonmark.node.* 4 | import org.commonmark.parser.Parser 5 | import java.nio.file.Path 6 | import kotlin.io.path.Path 7 | import kotlin.io.path.exists 8 | import kotlin.io.path.readText 9 | 10 | data class ReadmeIntroduction(val title: String, val content: String) 11 | 12 | class ReadmeParser(content: String) { 13 | private val parser: Parser = Parser.builder().build() 14 | private val node: Node = parser.parse(content) 15 | 16 | fun introduction(): ReadmeIntroduction { 17 | val visitor = IntroductionVisitor() 18 | node.accept(visitor) 19 | return visitor.introduction() 20 | } 21 | 22 | companion object { 23 | fun introduction(workdir: Path): String { 24 | var instr = ""; 25 | val readmeFile = Path(workdir.toString(), "README.md") 26 | if (readmeFile.exists()) { 27 | val readme = readmeFile.readText() 28 | val readmeParser = ReadmeParser(readme) 29 | val introduction = readmeParser.introduction() 30 | instr = "\nProject introduction: ${introduction.content}\n" 31 | } 32 | 33 | return instr 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/dynamic/DynamicContextFactory.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.dynamic.functions.ComateFunction 5 | import org.archguard.comate.dynamic.functions.DyFunction 6 | import org.archguard.comate.dynamic.functions.toSnakeCase 7 | import org.reflections.Reflections 8 | 9 | fun findClasses(): List> { 10 | val packageName = DyFunction::class.java.`package`.name 11 | val reflections = Reflections(packageName) 12 | 13 | val annotated: Set> = 14 | reflections.getTypesAnnotatedWith(ComateFunction::class.java) as Set> 15 | 16 | return annotated.toList() 17 | } 18 | 19 | 20 | class DynamicContextFactory(val context: ComateContext) { 21 | private var classMap: Map = mapOf() 22 | 23 | init { 24 | classMap = findClasses().associate { clazz -> 25 | val defaultConstructor = clazz.declaredConstructors[0] 26 | val dyFunction = defaultConstructor.newInstance(context) as DyFunction 27 | clazz.name.toSnakeCase() to dyFunction 28 | } 29 | } 30 | 31 | fun functions(): List { 32 | return this.classMap.map { 33 | it.value.define() 34 | } 35 | } 36 | 37 | fun tools(): Map { 38 | return this.classMap.map { 39 | it.key to it.value.define() 40 | }.toMap() 41 | } 42 | 43 | fun findByName(name: String): DyFunction? { 44 | return this.classMap[name] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/dynamic/DynamicContextManager.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic 2 | 3 | class DynamicContextManager { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/dynamic/functions/DesignSystemWithRequirementFunction.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic.functions 2 | 3 | import org.archguard.comate.action.DesignSystemPrompter 4 | import org.archguard.comate.command.ComateContext 5 | 6 | @ComateFunction 7 | class DesignSystemWithRequirementFunction(override val context: ComateContext) : DyFunction { 8 | override fun explain(): String { 9 | return "Design system architecture with requirement" 10 | } 11 | 12 | override fun execute(): FunctionResult.Success { 13 | val output = DesignSystemPrompter(context, context.strategy).execute() 14 | return FunctionResult.Success(output) 15 | } 16 | 17 | override fun parameters(): HashMap = hashMapOf( 18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/dynamic/functions/FoundationSpecGovernanceFunction.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic.functions 2 | 3 | import org.archguard.comate.action.FoundationGovernancePrompter 4 | import org.archguard.comate.command.ComateContext 5 | 6 | @ComateFunction 7 | class FoundationSpecGovernanceFunction(override val context: ComateContext) : DyFunction { 8 | override fun explain(): String { 9 | return "REST API Governance function, based on API Specification." 10 | } 11 | 12 | override fun execute(): FunctionResult.Success { 13 | val output = FoundationGovernancePrompter(context, context.strategy).execute() 14 | return FunctionResult.Success(output) 15 | } 16 | 17 | override fun parameters(): HashMap = hashMapOf( 18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/dynamic/functions/InitializeSystemFunction.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic.functions 2 | 3 | import org.archguard.action.checkout.GitCommandManager 4 | import org.archguard.action.checkout.GitSourceSettings 5 | import org.archguard.action.checkout.doCheckout 6 | import org.archguard.action.io.FileExt.mkdir 7 | import org.archguard.comate.command.ComateContext 8 | import java.io.File 9 | import kotlin.io.path.Path 10 | 11 | @ComateFunction 12 | class InitializeSystemFunction(override val context: ComateContext) : DyFunction { 13 | override val hidden: Boolean get() = true 14 | 15 | override fun explain(): String { 16 | return "Initialize system will clone the repository and setup it." 17 | } 18 | 19 | override fun execute(): FunctionResult { 20 | val settings = GitSourceSettings(context.projectRepo) 21 | // mkdir temp 22 | mkdir("temp") 23 | val workingDirectory = File("temp", settings.repositoryPath) 24 | 25 | mkdir(workingDirectory.toString()) 26 | val git = GitCommandManager(workingDirectory.toString()) 27 | 28 | doCheckout(git, settings) 29 | context.workdir = Path(workingDirectory.absolutePath.toString()) 30 | return FunctionResult.Success(true) 31 | } 32 | 33 | override fun parameters(): HashMap { 34 | return hashMapOf() 35 | } 36 | } -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/dynamic/functions/IntroduceSystemFunction.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic.functions 2 | 3 | import org.archguard.comate.action.IntroductionCodePrompt 4 | import org.archguard.comate.command.ComateContext 5 | 6 | @ComateFunction 7 | class IntroduceSystemFunction(override val context: ComateContext) : DyFunction { 8 | override fun explain(): String { 9 | return "Introduce system based on README.md, project dependencies." 10 | } 11 | 12 | override fun execute(): FunctionResult.Success { 13 | val output = IntroductionCodePrompt(context, context.strategy).execute() 14 | return FunctionResult.Success(output) 15 | } 16 | 17 | override fun parameters(): HashMap = hashMapOf( 18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/dynamic/functions/RestApiGovernanceFunction.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic.functions 2 | 3 | import org.archguard.comate.action.ApiGovernancePrompter 4 | import org.archguard.comate.command.ComateContext 5 | 6 | @ComateFunction 7 | class RestApiGovernanceFunction(override val context: ComateContext) : DyFunction { 8 | override fun explain(): String { 9 | return "REST API Governance function, based on API Specification." 10 | } 11 | 12 | override fun execute(): FunctionResult.Success { 13 | val output = ApiGovernancePrompter(context, context.strategy).execute() 14 | return FunctionResult.Success(output) 15 | } 16 | 17 | override fun parameters(): HashMap = hashMapOf( 18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/model/DomainModelScanner.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.model 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | import org.archguard.spec.execute.DomainModelScanner 5 | 6 | class DddDomainModelScanner( 7 | private val ds: List, 8 | ) : DomainModelScanner { 9 | override fun toUml(ds: List): String = UmlConverter().byFiles(ds) 10 | override fun scan(): List { 11 | val regex = Regex("(domain[s]?|element[s]?)(\\.)?", RegexOption.IGNORE_CASE) 12 | return ds.filter { regex.containsMatchIn(it.Package) } 13 | } 14 | } 15 | 16 | /** 17 | * It should be ThreeLayered, but MVC is more popular called. 18 | */ 19 | class MvcDomainModelScanner( 20 | private val ds: List, 21 | ) : DomainModelScanner { 22 | override fun toUml(ds: List): String = UmlConverter().byFiles(ds) 23 | override fun scan(): List { 24 | val regex = Regex("(element[s]?|domain)(\\.)?", RegexOption.IGNORE_CASE) 25 | return ds.filter { regex.containsMatchIn(it.Package) } 26 | } 27 | } 28 | 29 | class DomainModelFactory { 30 | companion object { 31 | fun generate(layeredStyle: String, ds: List): String { 32 | val scanner = when (layeredStyle) { 33 | "ddd" -> DddDomainModelScanner(ds) 34 | "mvc" -> MvcDomainModelScanner(ds) 35 | else -> throw IllegalArgumentException("domain model type $layeredStyle is not supported") 36 | } 37 | 38 | return scanner.toUml(scanner.scan()) 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/model/UmlConverter.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.model 2 | 3 | import chapi.domain.core.CodeDataStruct 4 | 5 | class UmlConverter { 6 | private val indent = """ """ 7 | 8 | fun byFile(element: CodeDataStruct): String { 9 | return """ 10 | @startuml 11 | ${byElement(element)} 12 | @enduml 13 | """.trimIndent() 14 | } 15 | 16 | fun byFiles(elements: List): String { 17 | return """ 18 | @startuml 19 | ${renderElements(elements)} 20 | @enduml 21 | """.trimIndent() 22 | } 23 | 24 | private fun renderElements(elements: List) = 25 | elements.joinToString("\n") { byElement(it) } 26 | 27 | private fun byElement(element: CodeDataStruct) = 28 | """ class ${element.NodeName} { 29 | ${renderFunctions(element)} 30 | }""" 31 | 32 | private fun renderFunctions(element: CodeDataStruct) = 33 | element.Functions.joinToString("\n") { " ${it.ReturnType} ${it.Name}()" } 34 | 35 | /** 36 | * output example: 37 | * @startuml 38 | * package "com.example" { 39 | * class TicketBooking 40 | * } 41 | * @enduml 42 | */ 43 | fun byPackage(elements: List): String { 44 | val packageMap = elements.filter { it.Package.isNotEmpty() }.groupBy { it.Package } 45 | 46 | return """ 47 | ${indent}@startuml 48 | ${byPackage(packageMap)} 49 | ${indent}@enduml 50 | """.trimIndent() 51 | } 52 | 53 | private fun byPackage(packageMap: Map>): String { 54 | return packageMap.map { (packageName, structs) -> 55 | """${indent}package "$packageName" { 56 | ${structs.joinToString("\n") { "$indent class ${it.NodeName}" }} 57 | ${indent}}""" 58 | }.joinToString("\n") 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/strategy/BasicPromptStrategy.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.strategy 2 | 3 | import org.archguard.comate.action.base.BaseTemplate 4 | 5 | class BasicPromptStrategy : Strategy { 6 | override fun prompt(template: BaseTemplate): String { 7 | var output = "" 8 | 9 | if (template.getRole().isNotEmpty()) { 10 | output += "You're an ${template.getRole()}," 11 | } 12 | 13 | if (template.getInstruction().isNotEmpty()) { 14 | output += template.getInstruction() 15 | } 16 | 17 | if (template.getRequirements().isNotEmpty()) { 18 | output += "Here is requirements: ${template.getRequirements()}\n" 19 | } 20 | 21 | if (template.getSample().isNotEmpty()) { 22 | output += "${template.getSample()}\n" 23 | } 24 | 25 | if (template.getExtendData().isNotEmpty()) { 26 | output += "${template.getExtendData()}\n" 27 | } 28 | 29 | return output 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/strategy/CodePromptStrategy.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.strategy 2 | 3 | import org.archguard.comate.action.base.BaseTemplate 4 | 5 | interface CodePromptStrategy : BaseTemplate { 6 | val strategy: Strategy 7 | fun execute(): String = strategy.prompt(this) 8 | } -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/strategy/Strategy.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.strategy 2 | 3 | import org.archguard.comate.action.base.BaseTemplate 4 | 5 | interface Strategy { 6 | fun prompt(template: BaseTemplate): String 7 | } -------------------------------------------------------------------------------- /comate-core/src/main/kotlin/org/archguard/comate/wrapper/ComateArchguardContext.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.wrapper 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.scanner.core.client.ArchGuardClient 5 | import org.archguard.scanner.core.client.EmptyArchGuardClient 6 | import org.archguard.scanner.core.sca.ScaContext 7 | import org.archguard.scanner.core.sourcecode.SourceCodeContext 8 | 9 | private val archGuardClient = EmptyArchGuardClient() 10 | 11 | class ComateScaContext( 12 | override val client: ArchGuardClient, 13 | override val path: String, 14 | override val language: String, 15 | ) : ScaContext { 16 | companion object { 17 | fun create(path: String, language: String): ScaContext { 18 | return ComateScaContext(archGuardClient, path, language) 19 | } 20 | } 21 | } 22 | 23 | class ComateSourceCodeContext( 24 | override val client: ArchGuardClient, 25 | override val features: List, 26 | override val language: String, 27 | override val path: String, 28 | ) : SourceCodeContext { 29 | companion object { 30 | fun create(path: String, language: String, features: List = listOf()): SourceCodeContext { 31 | return ComateSourceCodeContext(archGuardClient, features, language, path) 32 | } 33 | 34 | fun create(context: ComateContext): SourceCodeContext { 35 | return ComateSourceCodeContext(archGuardClient, listOf(), context.language, context.workdir.toString()) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/action/ApiGovernancePrompterTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.strategy.BasicPromptStrategy 5 | import org.junit.jupiter.api.Assertions.* 6 | import org.junit.jupiter.api.Test 7 | import java.nio.file.Path 8 | 9 | class ApiGovernancePrompterTest { 10 | @Test 11 | fun should_generate_correct_prompt_test() { 12 | val prompter = ApiGovernancePrompter(ComateContext(Path.of("."), "kotlin", null), BasicPromptStrategy()) 13 | 14 | val output = prompter.execute() 15 | assertEquals("""You're an Architecture Governance Expert,根据下面的信息,总结 RESTful API 的规范情况。Here is requirements: 16 | 1. API 应该符合基本 RESTful API 的规范,如 URI 构造、采用标准的 HTTP 方法、状态码、安全等。 17 | 2. 如果 result 是 true,请不要返回任何信息。 18 | 3. 如果 result 是 false,请返回不通过的原因,并根据 rule 提供符合规范的 API。 19 | 4. 你只返回如下的结果: 20 | 21 | ### 22 | - API `{api uri}` 不符合 { rule name } 规范,Rule: { rule },建议 API 修改为 {new api}。 23 | ### 24 | 25 | results: 26 | """, output) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/action/DesignSystemPrompterTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.strategy.BasicPromptStrategy 5 | import org.junit.jupiter.api.Assertions.* 6 | import org.junit.jupiter.api.Test 7 | import java.nio.file.Path 8 | 9 | class DesignSystemPrompterTest { 10 | @Test 11 | fun should_generate_correct_prompt_test() { 12 | val comateContext = 13 | ComateContext(Path.of("."), "kotlin", null, extArgs = mutableMapOf("actionInput" to "咖啡外卖")) 14 | val prompter = DesignSystemPrompter(comateContext, BasicPromptStrategy()) 15 | val output = prompter.execute() 16 | assertEquals( 17 | output, 18 | """You're an Architecture,根据详细分析如下的需求信息,设计完整的端到端需求用例。Here is requirements: 1. 请按如下的 DSL 格式返回,不做解释。 19 | 20 | 需求信息 如下: 21 | 22 | ### 23 | 咖啡外卖 24 | ### 25 | 26 | 27 | DSL 格式如下: 28 | ```kotlin 29 | caseflow("MovieTicketBooking", defaultActor = "User") { 30 | activity("AccountManage") { 31 | task("UserRegistration") { 32 | stories = listOf("Register with email", "Register with phone") 33 | } 34 | task("UserLogin") { 35 | stories += "Login to the website" 36 | // actor = "Admin" // if some task is actor-specific, you can specify it here 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | """ 43 | ) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/action/IntroductionPrompterTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.strategy.BasicPromptStrategy 5 | import org.junit.jupiter.api.Assertions.assertEquals 6 | import org.junit.jupiter.api.Test 7 | import java.nio.file.Path 8 | import kotlin.test.Ignore 9 | 10 | class IntroductionPrompterTest { 11 | // todo: fix for Windows 12 | @Test 13 | @Ignore 14 | fun should_generate_correct_prompt_test() { 15 | val workdir = javaClass.classLoader.getResource("hello-world")?.path.orEmpty() 16 | val introduction = IntroductionCodePrompt(ComateContext(Path.of(workdir), "kotlin", null), BasicPromptStrategy()) 17 | 18 | assertEquals( 19 | """ 20 | Project introduction: Reflekt is a compile-time reflection library that leverages the flows of the 21 | standard reflection approach and can find classes, objects (singleton classes) or functions 22 | by some conditions in compile-time. 23 | 24 | dependencies: 25 | 26 | | path | deps | 27 | | --- | --- | 28 | | build.gradle.kts | org.junit.jupiter:junit-jupiter, com.google.guava:guava | 29 | 30 | all channel types: [Website, Mobile App, Phone, Email, Social Media, Online Chat, In-person Store, Self-service Kiosk, Voice Assistant, Video Conferencing, SMS, Fax, Mail, Interactive Voice Response, Virtual Reality, Augmented Reality] 31 | """, introduction.getExtendData() 32 | ) 33 | } 34 | } -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/action/LayeredStylePromptTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.action 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.strategy.BasicPromptStrategy 5 | import org.junit.jupiter.api.Test 6 | import kotlin.io.path.Path 7 | 8 | class LayeredStylePromptTest { 9 | @Test 10 | fun should_throw_when_no_function_name_from_chapi() { 11 | val promptStrategy = BasicPromptStrategy() 12 | val basicPrompter = LayeredStylePrompt(ComateContext(Path("../"), "kotlin", null), promptStrategy) 13 | 14 | val output = basicPrompter.execute() 15 | println(output) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/code/FunctionCallChainTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.code 2 | 3 | import chapi.domain.core.CodeCall 4 | import chapi.domain.core.CodeDataStruct 5 | import chapi.domain.core.CodeFunction 6 | import org.junit.jupiter.api.Assertions.* 7 | 8 | class FunctionCallChainTest { 9 | @org.junit.jupiter.api.Test 10 | fun should_return_correct() { 11 | val source = CodeDataStruct( 12 | Package = "org.archguard", 13 | NodeName = "Source", 14 | Functions = listOf( 15 | CodeFunction( 16 | Name = "func1", 17 | Parameters = listOf(), 18 | FunctionCalls = listOf( 19 | CodeCall( 20 | Package = "org.archguard", 21 | NodeName = "Target", 22 | FunctionName = "func2", 23 | Parameters = listOf(), 24 | ), 25 | ), 26 | ) 27 | ), 28 | ) 29 | 30 | val target = CodeDataStruct( 31 | Package = "org.archguard", 32 | NodeName = "Target", 33 | Functions = listOf( 34 | CodeFunction( 35 | Name = "func2", 36 | Parameters = listOf(), 37 | ) 38 | ), 39 | ) 40 | 41 | val result = FunctionCallChain().analysis("org.archguard.Source.func1", listOf(source, target)) 42 | assertEquals("org.archguard.Source.func1 -> org.archguard.Target", result.toString()) 43 | } 44 | } -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/code/ProjectDependencyKtTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.code 2 | 3 | import org.archguard.scanner.core.sca.CompositionDependency 4 | import org.junit.jupiter.api.Test 5 | import kotlin.io.path.Path 6 | 7 | class ProjectDependencyKtTest { 8 | @Test 9 | fun should_return_correct() { 10 | val dep: List = listOf() 11 | val result = CompositionDependency.dependencyMapping(dep, Path(".")) 12 | 13 | assert(result.isEmpty()) 14 | } 15 | } -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/document/ReadmeParserTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.document 2 | 3 | import io.kotest.matchers.shouldBe 4 | import org.junit.jupiter.api.Assertions.* 5 | import kotlin.test.Test 6 | 7 | class ReadmeParserTest { 8 | @Test 9 | fun test_introduction() { 10 | val parser = ReadmeParser( 11 | """ 12 | [![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) 13 | 14 | # Reflekt 15 | 16 | Reflekt is a compile-time reflection library that leverages the flows of the 17 | standard reflection approach and can find classes, objects (singleton classes) or functions 18 | by some conditions in compile-time. 19 | 20 | Instead of relying on JVM reflection, Reflekt performs compile-time resolution of reflection queries 21 | using Kotlin compiler analysis, providing a convenient reflection API without actually using 22 | reflection. 23 | 24 | """.trimIndent() 25 | ) 26 | 27 | val introduction = parser.introduction() 28 | 29 | introduction.title shouldBe "Reflekt" 30 | introduction.content shouldBe """Reflekt is a compile-time reflection library that leverages the flows of the 31 | standard reflection approach and can find classes, objects (singleton classes) or functions 32 | by some conditions in compile-time.""" 33 | } 34 | 35 | @Test 36 | fun test_with_description_in_quote() { 37 | val parser = ReadmeParser( 38 | """ 39 | # ArchGuard CoMate 40 | 41 | > Co-mate is an AI-powered architecture copilot, design and governance tools. 42 | 43 | ## Todo 44 | """ 45 | ) 46 | val introduction = parser.introduction() 47 | 48 | introduction.title shouldBe "ArchGuard CoMate" 49 | introduction.content shouldBe """Co-mate is an AI-powered architecture copilot, design and governance tools.""" 50 | } 51 | } -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/dynamic/DynamicContextFactoryTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.archguard.comate.command.fakeComateContext 5 | import org.junit.jupiter.api.Assertions.assertEquals 6 | import org.junit.jupiter.api.Test 7 | import kotlin.io.path.Path 8 | import kotlin.test.assertNotNull 9 | 10 | class DynamicContextFactoryTest { 11 | @Test 12 | fun should_read_all_context_functions() { 13 | val context = fakeComateContext() 14 | val dynamicContextFactory = DynamicContextFactory(context) 15 | val functions = dynamicContextFactory.functions() 16 | 17 | assertEquals(functions.contains("introduce_system()"), true) 18 | } 19 | 20 | 21 | @Test 22 | fun should_find_by_function_name() { 23 | val context = fakeComateContext() 24 | val dynamicContextFactory = DynamicContextFactory(context) 25 | 26 | val introduceSystemFunction = dynamicContextFactory.findByName("introduce_system") 27 | assertNotNull(introduceSystemFunction) 28 | } 29 | } -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/dynamic/DynamicContextTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic 2 | 3 | import org.junit.jupiter.api.Assertions.* 4 | import org.junit.jupiter.api.Test 5 | 6 | class DynamicContextTest { 7 | 8 | @Test 9 | fun should_return_all_explains() { 10 | DynamicContext.explains().forEach { 11 | println(it) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /comate-core/src/test/kotlin/org/archguard/comate/dynamic/functions/IntroduceSystemFunctionTest.kt: -------------------------------------------------------------------------------- 1 | package org.archguard.comate.dynamic.functions 2 | 3 | import org.archguard.comate.command.ComateContext 4 | import org.junit.jupiter.api.Assertions.* 5 | import org.junit.jupiter.api.Test 6 | import kotlin.io.path.Path 7 | 8 | class IntroduceSystemFunctionTest { 9 | @Test 10 | fun should_get_analysis_system_function() { 11 | val context = ComateContext(Path("."), "kotlin", null) 12 | val introduceSystemFunction = IntroduceSystemFunction(context) 13 | 14 | val defineFunc = introduceSystemFunction.define() 15 | assertEquals("introduce_system()", defineFunc) 16 | } 17 | } -------------------------------------------------------------------------------- /comate-core/src/test/resources/hello-world/README.md: -------------------------------------------------------------------------------- 1 | [![Run deteKT](https://github.com/JetBrains-Research/reflekt/actions/workflows/detekt.yml/badge.svg)](https://github.com/JetBrains-Research/reflekt/actions/workflows/detekt.yml) 2 | [![Run diKTat](https://github.com/JetBrains-Research/reflekt/actions/workflows/diktat.yml/badge.svg)](https://github.com/JetBrains-Research/reflekt/actions/workflows/diktat.yml) 3 | 4 | # Reflekt 5 | 6 | Reflekt is a compile-time reflection library that leverages the flows of the 7 | standard reflection approach and can find classes, objects (singleton classes) or functions 8 | by some conditions in compile-time. 9 | 10 | Instead of relying on JVM reflection, Reflekt performs compile-time resolution of reflection queries 11 | using Kotlin compiler analysis, providing a convenient reflection API without actually using 12 | reflection. 13 | 14 | Reflekt is a joint project of [JetBrains Research](https://research.jetbrains.org/) and 15 | the [Kotless](https://github.com/JetBrains/kotless) team. The main reason for its creation was the 16 | necessity of GraalVM support in modern Java applications, especially on Serverless workloads. With 17 | the help of the Reflekt project, Kotless will be able to provide access to GraalVM to users of 18 | historically reflection-based frameworks such as Spring or their own Kotless DSL. 19 | 20 | We have implemented two approaches - searching classes\objects or functions via a limited DSL 21 | and by custom user condition via an extended DSL. 22 | The first one will be called `Reflekt`, and the second `SmartReflekt`. 23 | 24 | **Restrictions**. Reflekt analyses only `.kt` files (in the project and in the libraries); uses 25 | Kotlin `1.7.0`. Reflekt does not currently support incremental compilation. 26 | -------------------------------------------------------------------------------- /comate-core/src/test/resources/hello-world/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | testImplementation("org.junit.jupiter:junit-jupiter:5.9.1") 11 | 12 | implementation("com.google.guava:guava:31.1-jre") 13 | } 14 | 15 | application { 16 | mainClass.set("demo.App") 17 | } 18 | 19 | tasks.named("test") { 20 | useJUnitPlatform() 21 | } 22 | 23 | -------------------------------------------------------------------------------- /comate-gui/.env.example: -------------------------------------------------------------------------------- 1 | ## Get your OpenAI API Key 2 | OPENAI_API_KEY=XXXXXXXX 3 | OPENAI_PROXY_URL=XXXXXXXX 4 | 5 | ## Generate a random secret: https://generate-secret.vercel.app/32 6 | NEXTAUTH_SECRET=XXXXXXXX 7 | 8 | ## Only required for localhost 9 | NEXTAUTH_URL=http://localhost:3000 10 | 11 | COMATE_BACKEND=http://localhost:8844 12 | 13 | ## Create a GitHub OAuth app here: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app 14 | AUTH_GITHUB_ID=XXXXXXXX 15 | AUTH_GITHUB_SECRET=XXXXXXXX 16 | 17 | # instructions to create kv database here: https://vercel.com/docs/storage/vercel-kv/quickstart and 18 | KV_URL=XXXXXXXX 19 | KV_REST_API_URL=XXXXXXXX 20 | KV_REST_API_TOKEN=XXXXXXXX 21 | KV_REST_API_READ_ONLY_TOKEN=XXXXXXXX 22 | 23 | -------------------------------------------------------------------------------- /comate-gui/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/eslintrc", 3 | "root": true, 4 | "extends": [ 5 | "next/core-web-vitals", 6 | "prettier", 7 | "plugin:tailwindcss/recommended" 8 | ], 9 | "plugins": ["tailwindcss"], 10 | "rules": { 11 | "tailwindcss/no-custom-classname": "off" 12 | }, 13 | "settings": { 14 | "tailwindcss": { 15 | "callees": ["cn", "cva"], 16 | "config": "tailwind.config.js" 17 | } 18 | }, 19 | "overrides": [ 20 | { 21 | "files": ["*.ts", "*.tsx"], 22 | "parser": "@typescript-eslint/parser" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /comate-gui/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | 20 | # debug 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | .pnpm-debug.log* 25 | 26 | # local env files 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | 32 | # turbo 33 | .turbo 34 | 35 | .contentlayer 36 | .env 37 | .vercel 38 | .vscode -------------------------------------------------------------------------------- /comate-gui/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 Vercel, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /comate-gui/README.md: -------------------------------------------------------------------------------- 1 | # Comate GUI 2 | 3 | ## Running locally 4 | 5 | You will need to use the environment variables [defined in `.env.example`](.env.example) to run Next.js AI Chatbot. It's recommended you use [Vercel Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) for this, but a `.env` file is all that is necessary. 6 | 7 | > Note: You should not commit your `.env` file or it will expose secrets that will allow others to control access to your various OpenAI and authentication provider accounts. 8 | 9 | 1. Install Vercel CLI: `npm i -g vercel` 10 | 2. Link local instance with Vercel and GitHub accounts (creates `.vercel` directory): `vercel link` 11 | 3. Download your environment variables: `vercel env pull` 12 | 13 | ```bash 14 | npm install -g pnpm 15 | pnpm install 16 | pnpm dev 17 | ``` 18 | 19 | Your app template should now be running on [localhost:3000](http://localhost:3000/). 20 | -------------------------------------------------------------------------------- /comate-gui/app/api/action/tooling/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | 3 | export const runtime = 'edge' 4 | 5 | export async function POST(req: Request) { 6 | const json = await req.json() 7 | 8 | let baseUrl = process.env.COMATE_BACKEND || 'http://localhost:8844'; 9 | let url = `${baseUrl}/api/action/tooling` 10 | 11 | try { 12 | const response = await fetch(url, { 13 | method: 'POST', 14 | headers: { 15 | 'Content-Type': 'application/json' 16 | }, 17 | body: JSON.stringify(json), 18 | }); 19 | 20 | let responseJson = await response.json(); 21 | return NextResponse.json(responseJson, { status: 200 }) 22 | } catch (e) { 23 | return NextResponse.json({ error: e }, { status: 500 }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /comate-gui/app/api/auth/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | export { GET, POST } from '@/auth' 2 | export const runtime = 'edge' 3 | -------------------------------------------------------------------------------- /comate-gui/app/api/chat/route.ts: -------------------------------------------------------------------------------- 1 | import { searchTooling } from "@/app/api/common/search-tooling"; 2 | import { stream } from "@/app/api/chat/stream"; 3 | 4 | // import { auth } from '@/auth' 5 | // import { nanoid } from '@/lib/utils' 6 | 7 | export const runtime = 'edge' 8 | 9 | export async function POST(req: Request) { 10 | const json = await req.json() 11 | const { messages, previewToken } = json 12 | 13 | // if (messages.length == 1) { 14 | // get last messages 15 | 16 | let lastMessage = messages[messages.length - 1] 17 | // console.log(lastMessage) 18 | 19 | // todo: define prompt for our ai 20 | let isComatePrompt = lastMessage.content && lastMessage.content.startsWith("You're an Architecture"); 21 | if (!isComatePrompt) { 22 | // if output.prompt includes "HasMatchFunction: true" then we need to add a new message to the messages array 23 | let output = await searchTooling(lastMessage.content); 24 | lastMessage.content = output.prompt; 25 | } 26 | 27 | // const session = await auth() 28 | 29 | // if (process.env.VERCEL_ENV !== 'preview') { 30 | // if (session == null) { 31 | // return new Response('Unauthorized', { status: 401 }) 32 | // } 33 | // } 34 | 35 | // wrapper text to our server 36 | return await stream(previewToken, messages); 37 | } 38 | -------------------------------------------------------------------------------- /comate-gui/app/api/chat/stream.ts: -------------------------------------------------------------------------------- 1 | import {Message, OpenAIStream, StreamingTextResponse} from "ai"; 2 | import {Configuration, OpenAIApi} from "openai-edge"; 3 | 4 | export async function stream(apiKey: string, messages: Message[], isStream: boolean = true) { 5 | let basePath = process.env.OPENAI_PROXY_URL 6 | if (basePath == null) { 7 | basePath = 'https://api.openai.com' 8 | } 9 | 10 | const configuration = new Configuration({ 11 | apiKey: apiKey || process.env.OPENAI_API_KEY, 12 | basePath 13 | }) 14 | 15 | const openai = new OpenAIApi(configuration) 16 | 17 | const res = await openai.createChatCompletion({ 18 | model: 'gpt-3.5-turbo', 19 | messages: messages as any, 20 | temperature: 0.7, 21 | stream: isStream 22 | }) 23 | 24 | if (!isStream) { 25 | return res 26 | } 27 | 28 | const stream = OpenAIStream(res, {}) 29 | 30 | return new StreamingTextResponse(stream) 31 | } 32 | -------------------------------------------------------------------------------- /comate-gui/app/api/common/search-tooling.ts: -------------------------------------------------------------------------------- 1 | type BaseTool = { 2 | name: string, 3 | description: string, 4 | } 5 | 6 | type ToolingResponse = { 7 | prompt: string, 8 | tools: BaseTool[], 9 | } 10 | 11 | export async function searchTooling(text: string | undefined): Promise { 12 | let baseUrl = process.env.COMATE_BACKEND || 'http://localhost:8844'; 13 | let url = `${baseUrl}/api/prompt/tooling` 14 | 15 | console.log("searchTooling text: " + text); 16 | 17 | const res = await fetch(url, { 18 | method: 'POST', 19 | headers: { 20 | 'Content-Type': 'application/json' 21 | }, 22 | body: JSON.stringify({ text: text }) 23 | }); 24 | 25 | const json = await res.json() 26 | return json as ToolingResponse; 27 | } 28 | -------------------------------------------------------------------------------- /comate-gui/app/chat/[id]/page.tsx: -------------------------------------------------------------------------------- 1 | import { type Metadata } from 'next' 2 | import { notFound, redirect } from 'next/navigation' 3 | 4 | import { auth } from '@/auth' 5 | import { getChat } from '@/app/actions' 6 | import { Chat } from '@/components/chat' 7 | 8 | export const runtime = 'edge' 9 | export const preferredRegion = 'home' 10 | 11 | export interface ChatPageProps { 12 | params: { 13 | id: string 14 | } 15 | } 16 | 17 | export async function generateMetadata({ 18 | params 19 | }: ChatPageProps): Promise { 20 | const session = await auth() 21 | 22 | if (!session?.user) { 23 | return {} 24 | } 25 | 26 | const chat = await getChat(params.id, session.user.id) 27 | return { 28 | title: chat?.title.slice(0, 50) ?? 'Chat' 29 | } 30 | } 31 | 32 | export default async function ChatPage({ params }: ChatPageProps) { 33 | const session = await auth() 34 | 35 | if (!session?.user) { 36 | redirect(`/sign-in?next=/chat/${params.id}`) 37 | } 38 | 39 | const chat = await getChat(params.id, session.user.id) 40 | 41 | if (!chat) { 42 | notFound() 43 | } 44 | 45 | if (chat?.userId !== session?.user?.id) { 46 | notFound() 47 | } 48 | 49 | return 50 | } 51 | -------------------------------------------------------------------------------- /comate-gui/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 240 10% 3.9%; 9 | 10 | --muted: 240 4.8% 95.9%; 11 | --muted-foreground: 240 3.8% 46.1%; 12 | 13 | --popover: 0 0% 100%; 14 | --popover-foreground: 240 10% 3.9%; 15 | 16 | --card: 0 0% 100%; 17 | --card-foreground: 240 10% 3.9%; 18 | 19 | --border: 240 5.9% 90%; 20 | --input: 240 5.9% 90%; 21 | 22 | --primary: 240 5.9% 10%; 23 | --primary-foreground: 0 0% 98%; 24 | 25 | --secondary: 240 4.8% 95.9%; 26 | --secondary-foreground: 240 5.9% 10%; 27 | 28 | --accent: 240 4.8% 95.9%; 29 | --accent-foreground: ; 30 | 31 | --destructive: 0 84.2% 60.2%; 32 | --destructive-foreground: 0 0% 98%; 33 | 34 | --ring: 240 5% 64.9%; 35 | 36 | --radius: 0.5rem; 37 | } 38 | 39 | .dark { 40 | --background: 240 10% 3.9%; 41 | --foreground: 0 0% 98%; 42 | 43 | --muted: 240 3.7% 15.9%; 44 | --muted-foreground: 240 5% 64.9%; 45 | 46 | --popover: 240 10% 3.9%; 47 | --popover-foreground: 0 0% 98%; 48 | 49 | --card: 240 10% 3.9%; 50 | --card-foreground: 0 0% 98%; 51 | 52 | --border: 240 3.7% 15.9%; 53 | --input: 240 3.7% 15.9%; 54 | 55 | --primary: 0 0% 98%; 56 | --primary-foreground: 240 5.9% 10%; 57 | 58 | --secondary: 240 3.7% 15.9%; 59 | --secondary-foreground: 0 0% 98%; 60 | 61 | --accent: 240 3.7% 15.9%; 62 | --accent-foreground: ; 63 | 64 | --destructive: 0 62.8% 30.6%; 65 | --destructive-foreground: 0 85.7% 97.3%; 66 | 67 | --ring: 240 3.7% 15.9%; 68 | } 69 | } 70 | 71 | @layer base { 72 | * { 73 | @apply border-border; 74 | } 75 | body { 76 | @apply bg-background text-foreground; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /comate-gui/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next' 2 | 3 | import { Toaster } from 'react-hot-toast' 4 | 5 | import '@/app/globals.css' 6 | import { fontMono, fontSans } from '@/lib/fonts' 7 | import { cn } from '@/lib/utils' 8 | import { TailwindIndicator } from '@/components/tailwind-indicator' 9 | import { Providers } from '@/components/providers' 10 | import { Header } from '@/components/header' 11 | 12 | export const metadata: Metadata = { 13 | title: { 14 | default: 'ArchGuard Co-mate', 15 | template: `%s - ArchGuard Co-mate` 16 | }, 17 | description: 'An AI-powered architecture copilot, design and governance tools. ', 18 | themeColor: [ 19 | { media: '(prefers-color-scheme: light)', color: 'white' }, 20 | { media: '(prefers-color-scheme: dark)', color: 'black' } 21 | ], 22 | icons: { 23 | icon: '/favicon.ico', 24 | shortcut: '/favicon-16x16.png', 25 | apple: '/apple-touch-icon.png' 26 | } 27 | } 28 | 29 | interface RootLayoutProps { 30 | children: React.ReactNode 31 | } 32 | 33 | export default function RootLayout({ children }: RootLayoutProps) { 34 | return ( 35 | 36 | 37 | 44 | 45 | 46 |
47 | {/* @ts-ignore */} 48 |
49 |
{children}
50 |
51 | 52 |
53 | 54 | 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /comate-gui/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { nanoid } from '@/lib/utils' 2 | import { Chat } from '@/components/chat' 3 | 4 | export const runtime = 'edge' 5 | 6 | export default function IndexPage() { 7 | const id = nanoid() 8 | 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /comate-gui/assets/fonts/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unit-mesh/co-mate/4db062de589c6c67dccca7cb90917b0f778cc3fc/comate-gui/assets/fonts/Inter-Bold.woff -------------------------------------------------------------------------------- /comate-gui/assets/fonts/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unit-mesh/co-mate/4db062de589c6c67dccca7cb90917b0f778cc3fc/comate-gui/assets/fonts/Inter-Regular.woff -------------------------------------------------------------------------------- /comate-gui/auth.ts: -------------------------------------------------------------------------------- 1 | import NextAuth from 'next-auth' 2 | import GitHub from 'next-auth/providers/github' 3 | 4 | export const { 5 | handlers: { GET, POST }, 6 | auth, 7 | CSRF_experimental 8 | // @ts-ignore 9 | } = NextAuth({ 10 | // @ts-ignore 11 | providers: [GitHub], 12 | callbacks: { 13 | // @ts-ignore 14 | jwt: async ({ token, profile }) => { 15 | if (profile?.id) { 16 | token.id = profile.id 17 | token.image = profile.picture 18 | } 19 | return token 20 | } 21 | // @TODO 22 | // authorized({ request, auth }) { 23 | // return !!auth?.user 24 | // } 25 | }, 26 | pages: { 27 | signIn: '/sign-in' 28 | } 29 | }) 30 | -------------------------------------------------------------------------------- /comate-gui/components/button-scroll-to-bottom.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | 5 | import { cn } from '@/lib/utils' 6 | import { useAtBottom } from '@/lib/hooks/use-at-bottom' 7 | import { Button, type ButtonProps } from '@/components/ui/button' 8 | import { IconArrowDown } from '@/components/ui/icons' 9 | 10 | export function ButtonScrollToBottom({ className, ...props }: ButtonProps) { 11 | const isAtBottom = useAtBottom() 12 | 13 | return ( 14 | 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /comate-gui/components/chat-list.tsx: -------------------------------------------------------------------------------- 1 | import { type Message } from 'ai' 2 | 3 | import { Separator } from '@/components/ui/separator' 4 | import { ChatMessage } from '@/components/chat-message' 5 | 6 | export interface ChatList { 7 | messages: Message[] 8 | chatId?: string 9 | appendToChat?: (message: Message) => void 10 | } 11 | 12 | export function ChatList({ messages, chatId, appendToChat }: ChatList) { 13 | if (!messages.length) { 14 | return null 15 | } 16 | 17 | return ( 18 |
19 | {messages.map((message, index) => ( 20 |
21 | 22 | {index < messages.length - 1 && ( 23 | 24 | )} 25 |
26 | ))} 27 |
28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /comate-gui/components/chat-message-actions.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { type Message } from 'ai' 4 | 5 | import { Button } from '@/components/ui/button' 6 | import { IconCheck, IconCopy } from '@/components/ui/icons' 7 | import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard' 8 | import { cn } from '@/lib/utils' 9 | 10 | interface ChatMessageActionsProps extends React.ComponentProps<'div'> { 11 | message: Message 12 | } 13 | 14 | export function ChatMessageActions({ 15 | message, 16 | className, 17 | ...props 18 | }: ChatMessageActionsProps) { 19 | const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 }) 20 | 21 | return ( 22 |
29 | 37 |
38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /comate-gui/components/chat-message.tsx: -------------------------------------------------------------------------------- 1 | import { Message } from 'ai' 2 | 3 | import { cn } from '@/lib/utils' 4 | import { IconOpenAI, IconUser } from '@/components/ui/icons' 5 | import { ChatMessageActions } from '@/components/chat-message-actions' 6 | import { MessageRender } from "@/components/render/message-render"; 7 | 8 | export interface ChatMessageProps { 9 | message: Message 10 | chatId?: string 11 | appendToChat?: (message: Message) => void 12 | } 13 | 14 | export function ChatMessage({ message, chatId, appendToChat, ...props }: ChatMessageProps) { 15 | return ( 16 |
20 |
28 | {message.role === 'user' ? : } 29 |
30 |
31 | 32 | 33 |
34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /comate-gui/components/chat-scroll-anchor.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { useInView } from 'react-intersection-observer' 5 | 6 | import { useAtBottom } from '@/lib/hooks/use-at-bottom' 7 | 8 | interface ChatScrollAnchorProps { 9 | trackVisibility?: boolean 10 | } 11 | 12 | export function ChatScrollAnchor({ trackVisibility }: ChatScrollAnchorProps) { 13 | const isAtBottom = useAtBottom() 14 | const { ref, entry, inView } = useInView({ 15 | trackVisibility, 16 | delay: 100, 17 | rootMargin: '0px 0px -150px 0px' 18 | }) 19 | 20 | React.useEffect(() => { 21 | if (isAtBottom && trackVisibility && !inView) { 22 | entry?.target.scrollIntoView({ 23 | block: 'start' 24 | }) 25 | } 26 | }, [inView, entry, isAtBottom, trackVisibility]) 27 | 28 | return
29 | } 30 | -------------------------------------------------------------------------------- /comate-gui/components/external-link.tsx: -------------------------------------------------------------------------------- 1 | export function ExternalLink({ 2 | href, 3 | children 4 | }: { 5 | href: string 6 | children: React.ReactNode 7 | }) { 8 | return ( 9 | 14 | {children} 15 | 27 | 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /comate-gui/components/footer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { cn } from '@/lib/utils' 4 | import { ExternalLink } from '@/components/external-link' 5 | 6 | export function FooterText({ className, ...props }: React.ComponentProps<'p'>) { 7 | return ( 8 |

15 | Open source. 16 |

17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /comate-gui/components/login-button.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { signIn } from 'next-auth/react' 5 | 6 | import { cn } from '@/lib/utils' 7 | import { Button, type ButtonProps } from '@/components/ui/button' 8 | import { IconGitHub, IconSpinner } from '@/components/ui/icons' 9 | 10 | interface LoginButtonProps extends ButtonProps { 11 | showGithubIcon?: boolean 12 | text?: string 13 | } 14 | 15 | export function LoginButton({ 16 | text = 'Login with GitHub', 17 | showGithubIcon = true, 18 | className, 19 | ...props 20 | }: LoginButtonProps) { 21 | const [isLoading, setIsLoading] = React.useState(false) 22 | return ( 23 | 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /comate-gui/components/markdown.tsx: -------------------------------------------------------------------------------- 1 | import { FC, memo } from 'react' 2 | import ReactMarkdown, { Options } from 'react-markdown' 3 | 4 | export const MemoizedReactMarkdown: FC = memo( 5 | ReactMarkdown, 6 | (prevProps, nextProps) => 7 | prevProps.children === nextProps.children && 8 | prevProps.className === nextProps.className 9 | ) 10 | -------------------------------------------------------------------------------- /comate-gui/components/providers.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { ThemeProvider as NextThemesProvider } from 'next-themes' 5 | import { ThemeProviderProps } from 'next-themes/dist/types' 6 | 7 | import { TooltipProvider } from '@/components/ui/tooltip' 8 | 9 | export function Providers({ children, ...props }: ThemeProviderProps) { 10 | return ( 11 | 12 | {children} 13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /comate-gui/components/render/action-button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { ToolingThought } from "@/components/render/message-render"; 5 | 6 | export function ActionButton({ tooling, onResult }: { 7 | tooling: ToolingThought, 8 | onResult: (result: string) => void 9 | }) { 10 | const [isAnalysing, setIsAnalysing] = React.useState(false) 11 | 12 | return ; 26 | } 27 | -------------------------------------------------------------------------------- /comate-gui/components/render/markdown-render.tsx: -------------------------------------------------------------------------------- 1 | import { MemoizedReactMarkdown } from "@/components/markdown"; 2 | import remarkGfm from "remark-gfm"; 3 | import remarkMath from "remark-math"; 4 | import { CodeBlock } from "@/components/ui/codeblock"; 5 | 6 | export function MarkdownRender({ content }: { content: string }) { 7 | return {children}

13 | }, 14 | code({ node, inline, className, children, ...props }) { 15 | if (children.length) { 16 | if (children[0] == '▍') { 17 | return ( 18 | 19 | ) 20 | } 21 | 22 | children[0] = (children[0] as string).replace('`▍`', '▍') 23 | } 24 | 25 | const match = /language-(\w+)/.exec(className || '') 26 | 27 | if (inline) { 28 | return ( 29 | 30 | {children} 31 | 32 | ) 33 | } 34 | 35 | return ( 36 | 42 | ) 43 | } 44 | }} 45 | > 46 | {content} 47 |
; 48 | } 49 | -------------------------------------------------------------------------------- /comate-gui/components/sidebar-footer.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | 3 | export function SidebarFooter({ 4 | children, 5 | className, 6 | ...props 7 | }: React.ComponentProps<'div'>) { 8 | return ( 9 |
13 | {children} 14 |
15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /comate-gui/components/sidebar-list.tsx: -------------------------------------------------------------------------------- 1 | import { getChats, removeChat, shareChat } from '@/app/actions' 2 | import { SidebarActions } from '@/components/sidebar-actions' 3 | import { SidebarItem } from '@/components/sidebar-item' 4 | 5 | export interface SidebarListProps { 6 | userId?: string 7 | } 8 | 9 | export async function SidebarList({ userId }: SidebarListProps) { 10 | const chats = await getChats(userId) 11 | 12 | return ( 13 |
14 | {chats?.length ? ( 15 |
16 | {chats.map( 17 | chat => 18 | chat && ( 19 | 20 | 25 | 26 | ) 27 | )} 28 |
29 | ) : ( 30 |
31 |

No chat history

32 |
33 | )} 34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /comate-gui/components/sidebar.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | 5 | import { Button } from '@/components/ui/button' 6 | import { 7 | Sheet, 8 | SheetContent, 9 | SheetHeader, 10 | SheetTitle, 11 | SheetTrigger 12 | } from '@/components/ui/sheet' 13 | import { IconSidebar } from '@/components/ui/icons' 14 | 15 | export interface SidebarProps { 16 | children?: React.ReactNode 17 | } 18 | 19 | export function Sidebar({ children }: SidebarProps) { 20 | return ( 21 | 22 | 23 | 27 | 28 | 29 | 30 | Chat History 31 | 32 | {children} 33 | 34 | 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /comate-gui/components/tailwind-indicator.tsx: -------------------------------------------------------------------------------- 1 | export function TailwindIndicator() { 2 | if (process.env.NODE_ENV === 'production') return null 3 | 4 | return ( 5 |
6 |
xs
7 |
sm
8 |
md
9 |
lg
10 |
xl
11 |
2xl
12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /comate-gui/components/theme-toggle.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { useTheme } from 'next-themes' 5 | 6 | import { Button } from '@/components/ui/button' 7 | import { IconMoon, IconSun } from '@/components/ui/icons' 8 | 9 | export function ThemeToggle() { 10 | const { setTheme, theme } = useTheme() 11 | const [_, startTransition] = React.useTransition() 12 | 13 | return ( 14 | 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /comate-gui/components/toaster.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | export { Toaster } from 'react-hot-toast' 4 | -------------------------------------------------------------------------------- /comate-gui/components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { cva, type VariantProps } from 'class-variance-authority' 3 | 4 | import { cn } from '@/lib/utils' 5 | 6 | const badgeVariants = cva( 7 | 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', 8 | { 9 | variants: { 10 | variant: { 11 | default: 12 | 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80', 13 | secondary: 14 | 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', 15 | destructive: 16 | 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', 17 | outline: 'text-foreground' 18 | } 19 | }, 20 | defaultVariants: { 21 | variant: 'default' 22 | } 23 | } 24 | ) 25 | 26 | export interface BadgeProps 27 | extends React.HTMLAttributes, 28 | VariantProps {} 29 | 30 | function Badge({ className, variant, ...props }: BadgeProps) { 31 | return ( 32 |
33 | ) 34 | } 35 | 36 | export { Badge, badgeVariants } 37 | -------------------------------------------------------------------------------- /comate-gui/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | import { cn } from '@/lib/utils' 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ) 21 | } 22 | ) 23 | Input.displayName = 'Input' 24 | 25 | export { Input } 26 | -------------------------------------------------------------------------------- /comate-gui/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /comate-gui/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import * as SeparatorPrimitive from '@radix-ui/react-separator' 5 | 6 | import { cn } from '@/lib/utils' 7 | 8 | const Separator = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >( 12 | ( 13 | { className, orientation = 'horizontal', decorative = true, ...props }, 14 | ref 15 | ) => ( 16 | 27 | ) 28 | ) 29 | Separator.displayName = SeparatorPrimitive.Root.displayName 30 | 31 | export { Separator } 32 | -------------------------------------------------------------------------------- /comate-gui/components/ui/switch.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as SwitchPrimitives from "@radix-ui/react-switch" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Switch = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, ...props }, ref) => ( 12 | 20 | 25 | 26 | )) 27 | Switch.displayName = SwitchPrimitives.Root.displayName 28 | 29 | export { Switch } 30 | -------------------------------------------------------------------------------- /comate-gui/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | import { cn } from '@/lib/utils' 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |