├── .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 | [](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 | [](https://github.com/JetBrains-Research/reflekt/actions/workflows/detekt.yml)
2 | [](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 |
19 | )
20 | }
21 | )
22 | Textarea.displayName = 'Textarea'
23 |
24 | export { Textarea }
25 |
--------------------------------------------------------------------------------
/comate-gui/components/ui/tooltip.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 | import * as TooltipPrimitive from '@radix-ui/react-tooltip'
5 |
6 | import { cn } from '@/lib/utils'
7 |
8 | const TooltipProvider = TooltipPrimitive.Provider
9 |
10 | const Tooltip = TooltipPrimitive.Root
11 |
12 | const TooltipTrigger = TooltipPrimitive.Trigger
13 |
14 | const TooltipContent = React.forwardRef<
15 | React.ElementRef,
16 | React.ComponentPropsWithoutRef
17 | >(({ className, sideOffset = 4, ...props }, ref) => (
18 |
27 | ))
28 | TooltipContent.displayName = TooltipPrimitive.Content.displayName
29 |
30 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
31 |
--------------------------------------------------------------------------------
/comate-gui/lib/fonts.ts:
--------------------------------------------------------------------------------
1 | import { JetBrains_Mono as FontMono, Inter as FontSans } from 'next/font/google'
2 |
3 | export const fontSans = FontSans({
4 | subsets: ['latin'],
5 | variable: '--font-sans'
6 | })
7 |
8 | export const fontMono = FontMono({
9 | subsets: ['latin'],
10 | variable: '--font-mono'
11 | })
12 |
--------------------------------------------------------------------------------
/comate-gui/lib/hooks/use-at-bottom.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | export function useAtBottom(offset = 0) {
4 | const [isAtBottom, setIsAtBottom] = React.useState(false)
5 |
6 | React.useEffect(() => {
7 | const handleScroll = () => {
8 | setIsAtBottom(
9 | window.innerHeight + window.scrollY >=
10 | document.body.offsetHeight - offset
11 | )
12 | }
13 |
14 | window.addEventListener('scroll', handleScroll, { passive: true })
15 | handleScroll()
16 |
17 | return () => {
18 | window.removeEventListener('scroll', handleScroll)
19 | }
20 | }, [offset])
21 |
22 | return isAtBottom
23 | }
24 |
--------------------------------------------------------------------------------
/comate-gui/lib/hooks/use-copy-to-clipboard.tsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import * as React from 'react'
4 |
5 | export interface useCopyToClipboardProps {
6 | timeout?: number
7 | }
8 |
9 | export function useCopyToClipboard({
10 | timeout = 2000
11 | }: useCopyToClipboardProps) {
12 | const [isCopied, setIsCopied] = React.useState(false)
13 |
14 | const copyToClipboard = (value: string) => {
15 | if (
16 | typeof window === 'undefined' ||
17 | !navigator.clipboard ||
18 | !navigator.clipboard.writeText
19 | ) {
20 | return
21 | }
22 |
23 | navigator.clipboard.writeText(value).then(() => {
24 | setIsCopied(true)
25 |
26 | setTimeout(() => {
27 | setIsCopied(false)
28 | }, timeout)
29 | })
30 | }
31 |
32 | return { isCopied, copyToClipboard }
33 | }
34 |
--------------------------------------------------------------------------------
/comate-gui/lib/hooks/use-enter-submit.tsx:
--------------------------------------------------------------------------------
1 | import { useRef, type RefObject } from 'react'
2 |
3 | export function useEnterSubmit(): {
4 | formRef: RefObject
5 | onKeyDown: (event: React.KeyboardEvent) => void
6 | } {
7 | const formRef = useRef(null)
8 |
9 | const handleKeyDown = (
10 | event: React.KeyboardEvent
11 | ): void => {
12 | if (event.key === 'Enter' && !event.shiftKey) {
13 | formRef.current?.requestSubmit()
14 | event.preventDefault()
15 | }
16 | }
17 |
18 | return { formRef, onKeyDown: handleKeyDown }
19 | }
20 |
--------------------------------------------------------------------------------
/comate-gui/lib/hooks/use-local-storage.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | export const useLocalStorage = (
4 | key: string,
5 | initialValue: T
6 | ): [T, (value: T) => void] => {
7 | const [storedValue, setStoredValue] = useState(initialValue)
8 |
9 | useEffect(() => {
10 | // Retrieve from localStorage
11 | const item = window.localStorage.getItem(key)
12 | if (item) {
13 | setStoredValue(JSON.parse(item))
14 | }
15 | }, [key])
16 |
17 | const setValue = (value: T) => {
18 | // Save state
19 | setStoredValue(value)
20 | // Save to localStorage
21 | window.localStorage.setItem(key, JSON.stringify(value))
22 | }
23 | return [storedValue, setValue]
24 | }
25 |
--------------------------------------------------------------------------------
/comate-gui/lib/types.ts:
--------------------------------------------------------------------------------
1 | import { type Message } from 'ai'
2 |
3 | export interface Chat extends Record {
4 | id: string
5 | title: string
6 | createdAt: Date
7 | userId: string
8 | path: string
9 | messages: Message[]
10 | sharePath?: string
11 | }
12 |
13 | export type ServerActionResult = Promise<
14 | | Result
15 | | {
16 | error: string
17 | }
18 | >
19 |
--------------------------------------------------------------------------------
/comate-gui/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from 'clsx'
2 | import { customAlphabet } from 'nanoid'
3 | import { twMerge } from 'tailwind-merge'
4 |
5 | export function cn(...inputs: ClassValue[]) {
6 | return twMerge(clsx(inputs))
7 | }
8 |
9 | export const nanoid = customAlphabet(
10 | '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
11 | 7
12 | ) // 7-character random string
13 |
14 | const decoder = new TextDecoder()
15 | export function decodeAIStreamChunk(chunk: Uint8Array): string {
16 | return decoder.decode(chunk)
17 | }
18 |
19 | export async function fetcher(
20 | input: RequestInfo,
21 | init?: RequestInit
22 | ): Promise {
23 | const res = await fetch(input, init)
24 |
25 | if (!res.ok) {
26 | const json = await res.json()
27 | if (json.error) {
28 | const error = new Error(json.error) as Error & {
29 | status: number
30 | }
31 | error.status = res.status
32 | throw error
33 | } else {
34 | throw new Error('An unexpected error occurred')
35 | }
36 | }
37 |
38 | return res.json()
39 | }
40 |
41 | export function formatDate(input: string | number | Date): string {
42 | const date = new Date(input)
43 | return date.toLocaleDateString('en-US', {
44 | month: 'long',
45 | day: 'numeric',
46 | year: 'numeric'
47 | })
48 | }
49 |
--------------------------------------------------------------------------------
/comate-gui/middleware.ts:
--------------------------------------------------------------------------------
1 | export { auth as middleware } from './auth'
2 |
--------------------------------------------------------------------------------
/comate-gui/next-auth.d.ts:
--------------------------------------------------------------------------------
1 | import NextAuth, { DefaultSession } from 'next-auth'
2 |
3 | declare module 'next-auth' {
4 | /**
5 | * Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
6 | */
7 | interface Session {
8 | user: {
9 | /** The user's postal address. */
10 | id: string
11 | } & DefaultSession['user']
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/comate-gui/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/comate-gui/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | require('dotenv').config({ path: '~/.comate/.env' })
3 |
4 | module.exports = {
5 | reactStrictMode: true,
6 | experimental: {
7 | serverActions: true,
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/comate-gui/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/comate-gui/prettier.config.cjs:
--------------------------------------------------------------------------------
1 | /** @type {import('prettier').Config} */
2 | module.exports = {
3 | endOfLine: 'lf',
4 | semi: false,
5 | useTabs: false,
6 | singleQuote: true,
7 | arrowParens: 'avoid',
8 | tabWidth: 2,
9 | trailingComma: 'none',
10 | importOrder: [
11 | '^(react/(.*)$)|^(react$)',
12 | '^(next/(.*)$)|^(next$)',
13 | '',
14 | '',
15 | '^types$',
16 | '^@/types/(.*)$',
17 | '^@/config/(.*)$',
18 | '^@/lib/(.*)$',
19 | '^@/hooks/(.*)$',
20 | '^@/components/ui/(.*)$',
21 | '^@/components/(.*)$',
22 | '^@/registry/(.*)$',
23 | '^@/styles/(.*)$',
24 | '^@/app/(.*)$',
25 | '',
26 | '^[./]'
27 | ],
28 | importOrderSeparation: false,
29 | importOrderSortSpecifiers: true,
30 | importOrderBuiltinModulesToTop: true,
31 | importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'],
32 | importOrderMergeDuplicateImports: true,
33 | importOrderCombineTypeAndValueImports: true
34 | }
35 |
--------------------------------------------------------------------------------
/comate-gui/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unit-mesh/co-mate/4db062de589c6c67dccca7cb90917b0f778cc3fc/comate-gui/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/comate-gui/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unit-mesh/co-mate/4db062de589c6c67dccca7cb90917b0f778cc3fc/comate-gui/public/favicon-16x16.png
--------------------------------------------------------------------------------
/comate-gui/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unit-mesh/co-mate/4db062de589c6c67dccca7cb90917b0f778cc3fc/comate-gui/public/favicon.ico
--------------------------------------------------------------------------------
/comate-gui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "noEmit": true,
9 | "incremental": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "baseUrl": ".",
17 | "paths": {
18 | "@/*": ["./*"]
19 | },
20 | "plugins": [
21 | {
22 | "name": "next"
23 | }
24 | ],
25 | "strictNullChecks": true
26 | },
27 | "include": [
28 | "next-env.d.ts",
29 | "next-auth.d.ts",
30 | "**/*.ts",
31 | "**/*.tsx",
32 | ".next/types/**/*.ts"
33 | ],
34 | "exclude": ["node_modules"]
35 | }
36 |
--------------------------------------------------------------------------------
/comate-server/.gitignore:
--------------------------------------------------------------------------------
1 | temp
--------------------------------------------------------------------------------
/comate-server/build.gradle.kts:
--------------------------------------------------------------------------------
1 | val ktor_version = "2.3.1"
2 |
3 | @Suppress("DSL_SCOPE_VIOLATION")
4 | plugins {
5 | application
6 | alias(libs.plugins.jvm)
7 | alias(libs.plugins.serialization)
8 | id("io.ktor.plugin") version "2.3.1"
9 | }
10 |
11 | application {
12 | mainClass.set("io.ktor.server.netty.EngineMain")
13 | }
14 |
15 | repositories {
16 | maven {
17 | url = uri("https://maven.pkg.jetbrains.space/public/p/ktor/eap")
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation(projects.comateCore)
23 | implementation(projects.llmCore)
24 |
25 | implementation(projects.specLang)
26 | implementation(projects.specRuntime)
27 |
28 | implementation(libs.dotenv)
29 |
30 | // for backend code element
31 | implementation(libs.chapi.domain)
32 |
33 | implementation("io.ktor:ktor-server-core:$ktor_version")
34 | implementation("io.ktor:ktor-server-netty:$ktor_version")
35 | implementation("io.ktor:ktor-server-status-pages:$ktor_version")
36 | implementation("io.ktor:ktor-server-default-headers:$ktor_version")
37 |
38 | implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
39 | implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
40 | implementation("io.ktor:ktor-server-websockets:$ktor_version")
41 |
42 | implementation("io.ktor:ktor-server-cors:$ktor_version")
43 | implementation("io.ktor:ktor-server-compression:$ktor_version")
44 |
45 | implementation("ch.qos.logback:logback-classic:1.4.5")
46 |
47 | implementation("io.ktor:ktor-client-content-negotiation:$ktor_version") // for testing
48 | testImplementation("io.ktor:ktor-server-test-host:$ktor_version")
49 | testImplementation(libs.bundles.test)
50 |
51 | testImplementation("io.mockk:mockk:1.13.5")
52 | }
53 |
--------------------------------------------------------------------------------
/comate-server/src/main/kotlin/org/archguard/comate/server/Application.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server
2 |
3 | import io.ktor.serialization.kotlinx.json.*
4 | import io.ktor.server.application.*
5 | import io.ktor.server.plugins.compression.*
6 | import io.ktor.server.plugins.contentnegotiation.*
7 | import io.ktor.server.plugins.cors.routing.*
8 | import io.ktor.server.response.*
9 | import io.ktor.server.routing.*
10 | import kotlinx.serialization.json.Json
11 | import org.archguard.comate.server.action.routeForAction
12 | import org.archguard.comate.server.lang.routeForLang
13 | import org.archguard.comate.server.prompt.routeForPrompt
14 |
15 |
16 | fun main(args: Array): Unit = io.ktor.server.netty.EngineMain.main(args)
17 |
18 | fun Application.module() {
19 | install(CORS)
20 | install(Compression)
21 |
22 | install(ContentNegotiation) {
23 | json(Json {
24 | prettyPrint = true
25 | isLenient = true
26 | })
27 | }
28 |
29 | routing {
30 | // don't remove this route, it's for test server online.
31 | get("/") {
32 | call.respondText("Hello, world!")
33 | }
34 | routeForPrompt()
35 | routeForAction()
36 | routeForLang()
37 | }
38 | }
--------------------------------------------------------------------------------
/comate-server/src/main/kotlin/org/archguard/comate/server/action/ComateToolingAction.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.action
2 |
3 | import org.archguard.comate.command.ComateContext
4 | import org.archguard.comate.dynamic.functions.*
5 |
6 | enum class ComateToolingAction(val action: String) {
7 | INTRODUCE_SYSTEM(action = "introduce_system") {
8 | override fun execute(comateContext: ComateContext): FunctionResult.Success {
9 | InitializeSystemFunction(comateContext).execute()
10 | return IntroduceSystemFunction(comateContext).execute()
11 | }
12 | },
13 | REST_API_GOVERNANCE(action = "rest_api_governance") {
14 | override fun execute(comateContext: ComateContext): FunctionResult.Success {
15 | return RestApiGovernanceFunction(comateContext).execute()
16 | }
17 | },
18 | FOUNDATION_SPEC_GOVERNANCE(action = "foundation_spec_governance") {
19 | override fun execute(comateContext: ComateContext): FunctionResult.Success {
20 | return FoundationSpecGovernanceFunction(comateContext).execute()
21 | }
22 | },
23 | DESIGN_SYSTEM_WITH_REQUIREMENT(action = "design_system_with_requirement") {
24 | override fun execute(comateContext: ComateContext): FunctionResult.Success {
25 | return DesignSystemWithRequirementFunction(comateContext).execute()
26 | }
27 | },
28 | ;
29 |
30 | abstract fun execute(comateContext: ComateContext): FunctionResult.Success
31 |
32 | companion object {
33 | fun from(action: String): ComateToolingAction? {
34 | return values().find { it.action == action.lowercase() }
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/comate-server/src/main/kotlin/org/archguard/comate/server/action/dto/ActionResult.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.action.dto
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class ActionResult(val status: String, val action: String)
--------------------------------------------------------------------------------
/comate-server/src/main/kotlin/org/archguard/comate/server/action/dto/ToolingThought.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.action.dto
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class ToolingThought(val thought: String, val action: String, val actionInput: String)
--------------------------------------------------------------------------------
/comate-server/src/main/kotlin/org/archguard/comate/server/lang/LangController.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.lang
2 |
3 | import io.ktor.server.routing.*
4 |
5 | fun Route.routeForLang() {
6 | post("/api/lang/verify") {
7 | // todo: verify the code
8 | }
9 | }
--------------------------------------------------------------------------------
/comate-server/src/main/kotlin/org/archguard/comate/server/prompt/PromptController.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.prompt
2 |
3 | import io.ktor.server.application.*
4 | import io.ktor.server.request.*
5 | import io.ktor.server.response.*
6 | import io.ktor.server.routing.*
7 | import org.archguard.comate.command.fakeComateContext
8 | import org.archguard.comate.dynamic.DynamicContextFactory
9 | import org.archguard.comate.server.prompt.dto.PromptToolingReq
10 | import org.archguard.comate.server.prompt.dto.PromptToolingRes
11 | import org.archguard.comate.server.prompt.model.BaseTool
12 |
13 | fun Route.routeForPrompt() {
14 | val fakeFactory = DynamicContextFactory(fakeComateContext())
15 | val tools: List = fakeFactory.tools().map {
16 | BaseTool(it.key, it.value)
17 | }
18 |
19 | get("/api/prompt/tooling") {
20 | call.respond(PromptToolingRes("", tools))
21 | }
22 | post("/api/prompt/tooling") {
23 | val tooling = call.receive()
24 | val prompt = PromptingWrapper().functionSearch(tooling.text, tools)
25 |
26 | call.respond(PromptToolingRes(prompt, tools))
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/comate-server/src/main/kotlin/org/archguard/comate/server/prompt/dto/PromptToolingReq.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.prompt.dto
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class PromptToolingReq(val text: String)
--------------------------------------------------------------------------------
/comate-server/src/main/kotlin/org/archguard/comate/server/prompt/dto/PromptToolingRes.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.prompt.dto
2 |
3 | import kotlinx.serialization.Serializable
4 | import org.archguard.comate.server.prompt.model.BaseTool
5 |
6 | @Serializable
7 | data class PromptToolingRes(val prompt: String, val tools: List)
--------------------------------------------------------------------------------
/comate-server/src/main/kotlin/org/archguard/comate/server/prompt/model/BaseTool.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.prompt.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | class BaseTool(val name: String, val description: String)
--------------------------------------------------------------------------------
/comate-server/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8844
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [ org.archguard.comate.server.ApplicationKt.module ]
8 | }
9 | }
--------------------------------------------------------------------------------
/comate-server/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/comate-server/src/test/kotlin/org/archguard/comate/server/ApplicationKtTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server
2 |
3 | import io.ktor.client.request.*
4 | import io.ktor.client.statement.*
5 | import io.ktor.http.*
6 | import io.ktor.server.testing.*
7 | import org.junit.jupiter.api.Assertions.*
8 | import org.junit.jupiter.api.Test
9 |
10 | class ApplicationKtTest {
11 | @Test
12 | fun testRoot() = testApplication {
13 | val response = client.get("/")
14 | assertEquals(HttpStatusCode.OK, response.status)
15 | assertEquals("Hello, world!", response.bodyAsText())
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/comate-server/src/test/kotlin/org/archguard/comate/server/action/ComateToolingActionTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.action
2 |
3 | import org.junit.jupiter.api.Assertions.*
4 | import org.junit.jupiter.api.Test
5 |
6 | class ComateToolingActionTest {
7 | @Test
8 | fun should_get_class_by_value_of() {
9 | assertEquals(ComateToolingAction.INTRODUCE_SYSTEM, ComateToolingAction.from("INTRODUCE_SYSTEM"))
10 | assertEquals(ComateToolingAction.REST_API_GOVERNANCE, ComateToolingAction.from("REST_API_GOVERNANCE"))
11 | }
12 |
13 | @Test
14 | fun should_handle_by_null() {
15 | assertEquals(null, ComateToolingAction.from("NOT_EXIST"))
16 | }
17 | }
--------------------------------------------------------------------------------
/comate-server/src/test/kotlin/org/archguard/comate/server/prompt/PromptControllerKtTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.server.prompt
2 |
3 | import io.ktor.client.call.*
4 | import io.ktor.client.plugins.contentnegotiation.*
5 | import io.ktor.client.request.*
6 | import io.ktor.client.statement.*
7 | import io.ktor.http.*
8 | import io.ktor.serialization.kotlinx.json.*
9 | import io.ktor.server.testing.*
10 | import org.archguard.comate.server.action.ComateToolingAction
11 | import org.archguard.comate.server.prompt.dto.PromptToolingReq
12 | import org.archguard.comate.server.prompt.dto.PromptToolingRes
13 | import org.junit.jupiter.api.Assertions.assertEquals
14 | import org.junit.jupiter.api.Assertions.assertTrue
15 | import org.junit.jupiter.api.Test
16 |
17 | class PromptControllerKtTest {
18 | @Test
19 | fun should_return_all_tooling_api() = testApplication {
20 | val response = client.get("/api/prompt/tooling")
21 | assertEquals(HttpStatusCode.OK, response.status)
22 | val body = response.bodyAsText()
23 |
24 | assertTrue(body.contains(ComateToolingAction.REST_API_GOVERNANCE.action))
25 | assertTrue(body.contains(ComateToolingAction.FOUNDATION_SPEC_GOVERNANCE.action))
26 | }
27 |
28 | @Test
29 | fun should_return_prompt_text_from_post() = testApplication {
30 | val client = createClient {
31 | install(ContentNegotiation) {
32 | json()
33 | }
34 | }
35 |
36 | val response = client.post("/api/prompt/tooling") {
37 | contentType(ContentType.Application.Json)
38 | setBody(PromptToolingReq("rest api governance"))
39 | }
40 | assertEquals(HttpStatusCode.OK, response.status)
41 | val body = response.body()
42 |
43 | println(body)
44 | assertTrue(body.prompt.contains("Answer the following questions as best you can."))
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/docs/7-layer-openbanking.puml:
--------------------------------------------------------------------------------
1 | @startuml
2 |
3 | !define CHANNEL_LAYER_COLOR #F9E79F
4 | !define APPLICATION_LAYER_COLOR #82E0AA
5 | !define INTEGRATION_LAYER_COLOR #85C1E9
6 | !define BUSINESS_LOGIC_LAYER_COLOR #F5B7B1
7 | !define SYSTEM_OBJECT_STORAGE_LAYER_COLOR #D7BDE2
8 | !define CAPABILITY_LAYER_COLOR #FAD7A0
9 | !define CORE_PLATFORM_COLOR #A9DFBF
10 |
11 | rectangle "渠道层" as channel_layer #F9E79F {
12 | rectangle "网站" as website
13 | rectangle "移动应用" as mobile_app
14 | rectangle "电话" as phone
15 | rectangle "邮件" as email
16 | }
17 |
18 | rectangle "应用程序层" as application_layer #82E0AA {
19 | rectangle "ERP" as erp
20 | rectangle "CRM" as crm
21 | rectangle "SCM" as scm
22 | rectangle "OA" as oa
23 | }
24 |
25 | rectangle "集成层 (服务)" as integration_layer #85C1E9 {
26 | rectangle "SOA" as soa
27 | rectangle "微服务" as microservice
28 | }
29 |
30 | rectangle "业务逻辑层" as business_logic_layer #F5B7B1 {
31 | rectangle "订单管理" as order_management
32 | rectangle "客户管理" as customer_management
33 | rectangle "库存管理" as inventory_management
34 | }
35 |
36 | rectangle "系统对象存储集成层" as system_object_storage_layer #D7BDE2 {
37 | rectangle "数据库" as database
38 | rectangle "文件系统" as file_system
39 | }
40 |
41 | rectangle "能力层 (领域服务)" as capability_layer #FAD7A0 {
42 | rectangle "支付" as payment
43 | rectangle "物流" as logistics
44 | rectangle "推荐" as recommendation
45 | }
46 |
47 | rectangle "核心平台" as core_platform #A9DFBF {
48 | rectangle "身份认证" as authentication
49 | rectangle "日志管理" as log_management
50 | rectangle "监控" as monitoring
51 | }
52 |
53 | channel_layer -- application_layer
54 | application_layer -- integration_layer
55 | integration_layer -- business_logic_layer
56 | business_logic_layer -- system_object_storage_layer
57 | system_object_storage_layer -- capability_layer
58 | capability_layer -- core_platform
59 |
60 | @enduml
61 |
--------------------------------------------------------------------------------
/docs/7-levels.puml:
--------------------------------------------------------------------------------
1 | @startuml
2 |
3 | package "渠道层(Channel)" {
4 | [App]
5 | [Website]
6 | }
7 |
8 | package "应用程序层(Application)" {
9 | [CRM]
10 | [ERP]
11 | }
12 |
13 | package "集成层(Integration)" {
14 | [ESB]
15 | }
16 |
17 | package "业务逻辑层(Business Logic)" {
18 | [Business Process]
19 | [Business Rules]
20 | }
21 |
22 | package "系统对象存储集成层\n(Object/Data Persistence Integration)" {
23 | [RDBMS]
24 | [NoSQL]
25 | }
26 |
27 | package "能力层(Domain Services)" {
28 | [Order Service]
29 | [Account Service]
30 | [Product Service]
31 | }
32 |
33 | package "核心平台(Core Platform)" {
34 | [Authentication]
35 | [Logging]
36 | [Caching]
37 | }
38 |
39 | [App] --> [CRM]
40 | [Website] --> [ERP]
41 | [CRM] --> [ESB]
42 | [ERP] --> [ESB]
43 | [ESB] --> [Business Process]
44 | [Business Process] --> [Business Rules]
45 | [Business Process] --> [RDBMS]
46 | [Business Process] --> [NoSQL]
47 | [Order Service] --> [RDBMS]
48 | [Account Service] --> [NoSQL]
49 | [Product Service] --> [RDBMS]
50 | [Authentication] --> [Logging]
51 | [Business Process] --> [Caching]
52 |
53 | @enduml
--------------------------------------------------------------------------------
/docs/adr/0001-use-compose-for-gui.md:
--------------------------------------------------------------------------------
1 | # 1. use compose for GUI
2 |
3 | Date: 2023-05-30
4 |
5 | ## Status
6 |
7 | 2023-05-30 proposed
8 |
9 | 2023-05-30 deprecated
10 |
11 | ## Context
12 |
13 | As the GUI part of projects is getting more and more complex, we need a better way to manage it.
14 |
15 | So, we use Kotlin Compose to build the GUI, we can:
16 |
17 | - Use Kotlin to build the GUI
18 | - reUse the code in Android and Desktop
19 | - reUse exists Android UI code
20 |
21 | ## Decision
22 |
23 | Use Kotlin Compose to build the GUI.
24 |
25 |
--------------------------------------------------------------------------------
/docs/adr/0002-neighbor-architecture-generative-framework.md:
--------------------------------------------------------------------------------
1 | # 2. neighbor architecture generative frameworks
2 |
3 | Date: 2023-06-27
4 |
5 | ## Status
6 |
7 | 2023-06-27 proposed
8 |
9 | ## Context
10 |
11 | First
12 |
13 | use the follow format to define architecture for an online mall system,
14 |
15 | ```kotlin
16 | context("Cinema") {
17 | aggregate("Cinema") {
18 | entity("Cinema", "ScreeningRoom", "Seat")
19 | }
20 | }
21 | ```
22 |
23 | Output:
24 |
25 | ```kotlin
26 | context("OnlineMall") {
27 | aggregate("OnlineMall") {
28 | entity("Mall", "Store", "Product", "Customer", "Order")
29 | }
30 | }
31 | ```
32 |
33 | Second, create generate Customer entity, use Kotlin data class to representation.
34 |
35 |
36 | Third, according to the Customer entity, generate Product aggregate.
37 |
38 | ```kotlin
39 | data class Customer(
40 | val id: String,
41 | val name: String,
42 | val email: String,
43 | val address: String,
44 | val phone: String,
45 | val dateOfBirth: LocalDate
46 | )
47 | ```
48 |
49 | Output:
50 |
51 | ```kotlin
52 | data class Product(
53 | val id: String,
54 | val name: String,
55 | val description: String,
56 | val price: Double,
57 | val quantityAvailable: Int
58 | )
59 | ```
60 |
61 | ## Decision
62 |
63 | Decision here...
64 |
65 | ## Consequences
66 |
67 | Consequences here...
68 |
--------------------------------------------------------------------------------
/docs/adr/0004-enterprise-architecture-less-in-co-mate.md:
--------------------------------------------------------------------------------
1 | # 4. Enterprise Architecture less in co-mate
2 |
3 | Date: 2023-06-28
4 |
5 | ## Status
6 |
7 | 2023-06-28 proposed
8 |
9 | ## Context
10 |
11 | Since we are still not good at EA, we need to use less EA in co-mate.
12 |
13 | ## Decision
14 |
15 | Decision here...
16 |
17 | ## Consequences
18 |
19 | Consequences here...
20 |
--------------------------------------------------------------------------------
/docs/adr/README.md:
--------------------------------------------------------------------------------
1 | # Architecture Decision Records
2 |
3 | * [1. use-compose-for-gui](0001-use-compose-for-gui.md)
4 | * [2. neighbor-architecture-generative-framework](0002-neighbor-architecture-generative-framework.md)
5 | * [3. separate-implmentation-&-design-architecture](0003-separate-implmentation-&-design-architecture.md)
6 | * [4. enterprise-architecture-less-in-co-mate](0004-enterprise-architecture-less-in-co-mate.md)
7 |
--------------------------------------------------------------------------------
/docs/docs.md:
--------------------------------------------------------------------------------
1 | ## Docs
2 |
3 | ### 擅长
4 |
5 | 1. 约束步骤。Step by Step,工程化的分析,给出足够多的上下文。
6 | - 信息没给够,不知道怎么做。
7 | - 缺少模型以外的信息。
8 | 2. 围绕一个软件的需求,能否给够相关信息。
9 | 3. 擅长的是:没有标准答案,总结、分类、提取信息,可以利用的原子能力。
10 | - 列出所有原能力(类似于微服务、背后能利用的能力)
11 | 4. Prompt as Code,Building Block 变了,作为基础能力
12 | - 例如,以前 A, B,C 能力。
13 | 5. 某些特定的就不擅长?
14 | - 传统工具:算法
15 | - MapReduce 的方式。
16 | - 函数式编程是不是更适合大语言模型。
17 | 6. 是不是所有应用和场景都能结合 LLM?
18 | 7. 检索增强:给模型提供的工具。
19 | 8. 原 AI 模型是不是真的高质量的语料
20 | - 代码是不是真的好,如何筛选
21 | - 代码质量还会不会很重要?
22 | 9. 让 AI 模型再作为人来进行监督。
23 |
24 | ### 1. 分析阶段:设计
25 |
26 | 如何分解 LLM,提取原子能力(总结、分类、提取信息),类似于微服务。我们需要基于约束好工程化步骤,结合我们的上下文,可以构建出更理想的 AI 应用。
27 |
28 | 在未来(LLM 上下文下),分析、设计软件的思路:解构需要解决的问题:
29 |
30 | - 需要什么的基础 LLM 能力(Building Block:总结、分类、提取、翻译、逻辑推理)
31 | - 哪些需要补充数据(上下文)
32 | - 哪些需要插件/原始工具(Wolfram、日志分析)
33 | - 哪些需要传统的算法。
34 |
35 | ### 2. 是不是所有应用和场景都能结合 LLM?
36 |
37 | 在不擅长的场景下:LLM 可以作为调度器。如实时性要求高的决策,网络相关的?(不一定通过 LLM 而是深度学习模型,如淘宝)。
38 |
39 | 函数式编程是不是更适合 LLM 的编程范式? 如 MapReduce 方式的 LangChain。
40 |
41 | 其它场景下,诸如编码可以结合插件化的方式、CRUD 就擅长。代码是比较精确的、质量高的,容易验证。
42 |
43 | ### 3. 多模型架构
44 |
45 | 区分 AI 模型的能力,解决问题的领域能力,进行匹配。
46 |
47 | 1. AI 模型分工。不同的领域需要不同的模型知识。如大部分场景 GPT 是 OK 的,成本高慢,但是像 Copilot 采用的 Codex 速度快、结果好。
48 | - 优化的时候,低成本模型负责一部分的工作。
49 | 2. AI 相互监督。可以利用同一个模型,来强化问题解决。比如需求分析、写代码、测试,让几个 Prompt 让 AI 写,给出结果,然后人工选择。或者 Code Review。
50 |
51 |
--------------------------------------------------------------------------------
/docs/dynamic-context.md:
--------------------------------------------------------------------------------
1 | # Dynamic Context
2 |
3 | ## Language API
4 |
5 | - Nature Language In API
6 | - 语言转 Command:分析这个系统。
7 | - Nature Language Out API
8 | - 根据用户的需求,选择合适的分析模型数据和模型函数。
9 | - Dynamic Context
10 | - 返回一个 UI 确认表单。
11 | - Nature Re-Try API
12 | - 你返回的结果不对,请认真按先前的要求重新返回。
13 | - Spec Language API
14 | - Foundation DSL
15 | - Domain DSL
16 | - RestAPI DSL
17 |
18 | ## Dynamic Context
19 |
20 | 对话:
21 |
22 | Q:你好,我是 Co-mate,你想要什么?
23 | A: 帮我分析一下这个系统。https://github.com/archguard/ddd-monolithic-code-sample
24 | ,> Function Calling
25 | Q: 请确认一下,以下是否是你需要的信息?
26 | 成功 ,> UI, Scanning.
27 | 失败 <, 你返回的结果不对,请认真按先前的要求重新返回。
28 | Q: 调用 Spec DSL
29 |
30 | ### Prompt
31 |
32 | 你是一个系统分析师,你需要认真分析用户的需求,并按要求返回结果。要求:
33 |
34 | 1. 如果用户的需求不明确,或者已有的数据不支持,请提示用户。返回示例:您的输入不正确,请重新输入。
35 | 2. 如果已有的数据类型支持,但是没有支持的函数,请返回数据模型。返回示例:```data\ndomain_model```
36 | 3. 如果已有的函数能处理,请直接返回函数名和参数。返回示例:```function\nintroduce_system("https://github.com/xxx/xxx")```
37 | 4. 请不要返回不存在的数据类型和函数。
38 | 5. 你只返回结果,不要解释。
39 |
40 | 以下是支持的数据类型:
41 |
42 | ```
43 | ApiSpecification,ApiSpecification is a specification of a REST API.
44 | DomainModel,DomainModel is a define for domain element.
45 | PackageInfo,PackageInfo is a define for ALL package info.
46 | README,README file contain project introduction.
47 | FoundationSpecification,FoundationSpecification is a specification of layered architecture, naming style, package naming, class naming.
48 | ProjectDependency,ProjectDependency include all used defines
49 | DomainSpecification,DomainSpecification is a specification of a domain model element.
50 | ```
51 |
52 | 以下是支持的函数:
53 |
54 | ```
55 | introduce_system(String url),introduce_system is a function to introduce a system.
56 | ```
57 |
58 | 用户的需求是:
59 |
60 | ###
61 | 这个系统的 REST API 是否符合规范。
62 | ###
63 |
--------------------------------------------------------------------------------
/docs/governance/README.md:
--------------------------------------------------------------------------------
1 | # Principles of Governance
2 |
3 |
4 | ### Sample from specs
5 |
6 | URI: http://example.com/api/petstore/v1/pets/dogs?breed=golden-retriever
7 |
8 | ### Action for URI
9 |
10 | - Not Delete
11 |
12 | ### All Enum in List
13 |
14 | ```
15 | enum class HttpStatusCode(val value: Int, val message: String) {
16 | OK(200, "OK"),
17 | CREATED(201, "Created"),
18 | NO_CONTENT(204, "No Content"),
19 | NOT_MODIFIED(304, "Not Modified"),
20 | BAD_REQUEST(400, "Bad Request"),
21 | UNAUTHORIZED(401, "Unauthorized"),
22 | FORBIDDEN(403, "Forbidden"),
23 | NOT_FOUND(404, "Not Found"),
24 | UNPROCESSABLE_ENTITY(422, "Unprocessable Entity"),
25 | INTERNAL_SERVER_ERROR(500, "Internal Server Error")
26 | }
27 | ```
28 |
29 | ### Specific case for rule
30 |
31 | Security
32 |
33 | indepedence
--------------------------------------------------------------------------------
/docs/prompt/README.md:
--------------------------------------------------------------------------------
1 | # Prompt
2 |
3 |
4 | https://github.com/Significant-Gravitas/Auto-GPT/blob/30f153e695677b2986375aa224df7cfafb861efb/autogpt/config/ai_config.py
5 | https://github.com/Significant-Gravitas/Auto-GPT/blob/30f153e695677b2986375aa224df7cfafb861efb/autogpt/config/prompt_config.py
6 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 |
3 | kotlin.version=1.8.20
4 | agp.version=7.3.0
5 | compose.version=1.4.0
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unit-mesh/co-mate/4db062de589c6c67dccca7cb90917b0f778cc3fc/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
4 | networkTimeout=10000
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/legacy/comate-gui/README.md:
--------------------------------------------------------------------------------
1 | # Comate GUI
2 |
3 | - Storage
4 | - [JetPack DataStore](https://developer.android.com/topic/libraries/architecture/datastore?hl=zh-cn)
5 |
6 | ## Refs
7 |
8 | Refs: https://github.com/lambiengcode/compose-chatgpt-kotlin-android-chatbot
9 |
10 | - [Compose RichText](https://github.com/halilozercan/compose-richtext)
11 | - [Navigation](https://github.com/adrielcafe/voyager)
12 |
--------------------------------------------------------------------------------
/legacy/comate-gui/src/jvmMain/kotlin/model/ConversationModel.kt:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import java.util.*
4 |
5 | data class ConversationModel(
6 | var id: String = Date().time.toString(),
7 | var title: String = "",
8 | var createdAt: Date = Date(),
9 | )
--------------------------------------------------------------------------------
/legacy/comate-gui/src/jvmMain/kotlin/model/MessageModel.kt:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import java.util.*
4 |
5 | data class MessageModel(
6 | var id: String = Date().time.toString(),
7 | var conversationId: String = "",
8 | var question: String = "",
9 | var answer: String = "",
10 | var createdAt: Date = Date(),
11 | )
--------------------------------------------------------------------------------
/legacy/comate-gui/src/jvmMain/kotlin/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | val Purple80 = Color(0xFFD0BCFF)
6 | val PurpleGrey80 = Color(0xFFCCC2DC)
7 | val Pink80 = Color(0xFFEFB8C8)
8 |
9 | val Purple40 = Color(0xFF6650a4)
10 | val PurpleGrey40 = Color(0xFF625b71)
11 | val Pink40 = Color(0xFF7D5260)
12 |
13 | val PrimaryColor = Color(0xFF1DA1F2)
14 |
15 | val BackGroundColor = Color(0xFF14171A)
16 | val BackGroundMessageHuman = Color(0xFFE2F0E9)
17 | val BackGroundMessageGPT = Color(0xFF22252A)
18 | val ColorTextHuman = Color(0xFF3D3D4E)
19 | val ColorTextGPT = Color(0xFFFFFFF2)
20 |
--------------------------------------------------------------------------------
/legacy/comate-gui/src/jvmMain/kotlin/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package theme
2 |
3 | import androidx.compose.foundation.isSystemInDarkTheme
4 | import androidx.compose.material.Colors
5 | import androidx.compose.material.MaterialTheme
6 | import androidx.compose.material.darkColors
7 | import androidx.compose.material.lightColors
8 | import androidx.compose.runtime.Composable
9 |
10 | @Composable
11 | fun LightTheme(
12 | darkTheme: Boolean = isSystemInDarkTheme(),
13 | content: @Composable () -> Unit
14 | ) {
15 | val colors: Colors = if (darkTheme) {
16 | darkColors()
17 | } else {
18 | lightColors()
19 | }
20 |
21 | MaterialTheme(
22 | colors = colors,
23 | content = content,
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/llm-core/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) Harrison Chase
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/llm-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(projects.specLang)
9 | implementation(libs.kotlin.stdlib)
10 | implementation(libs.coroutines.core)
11 |
12 | implementation(libs.bundles.openai)
13 | implementation(libs.jtokkit)
14 |
15 | implementation("ch.qos.logback:logback-classic:1.4.5")
16 |
17 | testImplementation(libs.bundles.test)
18 | testRuntimeOnly(libs.test.junit.engine)
19 | }
20 |
--------------------------------------------------------------------------------
/llm-core/src/main/kotlin/org/archguard/comate/connector/LlmConnector.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.connector
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import java.time.Duration
5 |
6 | interface LlmConnector {
7 | val timeout: Duration
8 | get() = Duration.ofSeconds(600)
9 |
10 | fun prompt(text: String): String
11 | fun stream(text: String): Flow
12 | }
--------------------------------------------------------------------------------
/llm-core/src/main/kotlin/org/archguard/comate/token/LlmTokenCalculate.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.token
2 |
3 | import com.knuddels.jtokkit.Encodings
4 | import com.knuddels.jtokkit.api.Encoding
5 | import com.knuddels.jtokkit.api.EncodingRegistry
6 | import com.knuddels.jtokkit.api.ModelType
7 |
8 |
9 | class LlmTokenCalculate(override val maxToken: Int, val modelType: String) : TokenCalculate {
10 | var registry: EncodingRegistry = Encodings.newDefaultEncodingRegistry()
11 |
12 | override fun calculate(input: String): Int {
13 | val modelType = ModelType.fromName(modelType)
14 | if (modelType.isPresent) {
15 | val enc: Encoding = registry.getEncodingForModel(modelType.get())
16 | return enc.encode(input).size
17 | }
18 |
19 | throw IllegalArgumentException("Model type $modelType not found")
20 | }
21 | }
--------------------------------------------------------------------------------
/llm-core/src/main/kotlin/org/archguard/comate/token/TokenCalculate.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.token
2 |
3 | interface TokenCalculate {
4 | val maxToken: Int
5 | fun calculate(input: String): Int
6 | fun isOverLimit(input: String): Boolean {
7 | return calculate(input) > maxToken
8 | }
9 | }
--------------------------------------------------------------------------------
/llm-core/src/test/kotlin/org/archguard/comate/connector/OpenAIConnectorTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.connector
2 |
3 | import org.junit.jupiter.api.Assertions.assertEquals
4 | import org.junit.jupiter.api.Test
5 |
6 | class OpenAIConnectorTest {
7 |
8 | }
--------------------------------------------------------------------------------
/llm-core/src/test/kotlin/org/archguard/comate/token/LlmTokenCalculateTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.token
2 |
3 | import org.junit.jupiter.api.Assertions.*
4 | import org.junit.jupiter.api.Test
5 |
6 | class LlmTokenCalculateTest {
7 | @Test
8 | fun should_success_when_calculate() {
9 | val calculate = LlmTokenCalculate(100, "gpt-3.5-turbo")
10 | val result = calculate.calculate("public class Test {}")
11 | assertEquals(4, result)
12 | }
13 |
14 | @Test
15 | fun should_throw_exception_when_model_not_exist() {
16 | val calculate = LlmTokenCalculate(100, "gpt-3.5")
17 | assertThrows(IllegalArgumentException::class.java) {
18 | calculate.calculate("public class Test {}")
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/llm-semantic/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(projects.specLang)
9 | implementation(libs.kotlin.stdlib)
10 | implementation(libs.coroutines.core)
11 |
12 | implementation(libs.bundles.openai)
13 |
14 | implementation(libs.onnxruntime)
15 | implementation(libs.huggingface.tokenizers)
16 | implementation(libs.jtokkit)
17 |
18 | testImplementation(libs.bundles.test)
19 | testRuntimeOnly(libs.test.junit.engine)
20 | }
21 |
--------------------------------------------------------------------------------
/llm-semantic/src/main/kotlin/org/archguard/comate/smart/CosineSimilarity.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.comate.smart
2 |
3 | import kotlin.math.sqrt
4 |
5 | fun cosineSimilarity(first: FloatArray, second: FloatArray): Float {
6 | // require(first.size == second.size) { "first and second must have the same size" }
7 | var dotProduct = 0f
8 | var normA = 0f
9 | var normB = 0f
10 |
11 | for (i in first.indices) {
12 | dotProduct += first[i] * second[i]
13 | normA += first[i] * first[i]
14 | normB += second[i] * second[i]
15 | }
16 |
17 | val denominator = sqrt(normA) * sqrt(normB)
18 | return if (denominator == 0f) 0f else dotProduct / denominator
19 | }
--------------------------------------------------------------------------------
/llm-semantic/src/main/resources/model/model.onnx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unit-mesh/co-mate/4db062de589c6c67dccca7cb90917b0f778cc3fc/llm-semantic/src/main/resources/model/model.onnx
--------------------------------------------------------------------------------
/llm-semantic/src/main/resources/model/special_tokens_map.json:
--------------------------------------------------------------------------------
1 | {
2 | "cls_token": "[CLS]",
3 | "mask_token": "[MASK]",
4 | "pad_token": "[PAD]",
5 | "sep_token": "[SEP]",
6 | "unk_token": "[UNK]"
7 | }
8 |
--------------------------------------------------------------------------------
/llm-semantic/src/main/resources/model/tokenizer_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "cls_token": "[CLS]",
3 | "do_basic_tokenize": true,
4 | "do_lower_case": true,
5 | "mask_token": "[MASK]",
6 | "model_max_length": 512,
7 | "name_or_path": "sentence-transformers/all-MiniLM-L6-v2",
8 | "never_split": null,
9 | "pad_token": "[PAD]",
10 | "sep_token": "[SEP]",
11 | "special_tokens_map_file": "/Users/gabriel/.cache/huggingface/hub/models--sentence-transformers--all-MiniLM-L6-v2/snapshots/7dbbc90392e2f80f3d3c277d6e90027e55de9125/special_tokens_map.json",
12 | "strip_accents": null,
13 | "tokenize_chinese_chars": true,
14 | "tokenizer_class": "BertTokenizer",
15 | "unk_token": "[UNK]"
16 | }
17 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | @file:Suppress("UnstableApiUsage")
2 |
3 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
4 |
5 | rootProject.name = "Comate"
6 |
7 | pluginManagement {
8 | repositories {
9 | google()
10 | gradlePluginPortal()
11 | mavenCentral()
12 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
13 | }
14 |
15 | plugins {
16 | kotlin("multiplatform").version(extra["kotlin.version"] as String)
17 | id("org.jetbrains.compose").version(extra["compose.version"] as String)
18 | }
19 | }
20 |
21 | dependencyResolutionManagement {
22 | repositories {
23 | mavenCentral()
24 | mavenLocal()
25 | }
26 | }
27 |
28 | plugins {
29 | id("org.gradle.toolchains.foojay-resolver-convention") version ("0.4.0")
30 | }
31 |
32 |
33 | include(":architecture")
34 | include(":llm-core")
35 | include(":llm-semantic")
36 |
37 | include(":comate-core")
38 | //include(":comate-gui")
39 | include(":comate-cli")
40 | include(":comate-server")
41 |
42 | include(":spec-lang")
43 | include(":spec-partitioner")
44 | include(":spec-runtime")
45 |
--------------------------------------------------------------------------------
/spec-lang/README.md:
--------------------------------------------------------------------------------
1 | # Spec Language
2 |
3 | Spec action for spec execution.
4 |
5 | ## Overview
6 |
7 | The meta action is a dynamic action that can be used to execute a spec.
8 |
--------------------------------------------------------------------------------
/spec-lang/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(projects.architecture)
9 | implementation(libs.kotlin.stdlib)
10 | implementation(libs.serialization.json)
11 |
12 | // for backend code element
13 | implementation(libs.chapi.domain)
14 |
15 | testImplementation(libs.bundles.test)
16 |
17 | testRuntimeOnly(libs.test.junit.engine)
18 | }
19 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/base/LlmRule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.base
2 |
3 | interface LlmRule : Rule {
4 | override fun exec(input: T): List {
5 | return exec(input)
6 | }
7 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/base/Rule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.base
2 |
3 | interface Rule {
4 | val actionName: String
5 | fun exec(input: T): Any {
6 | return false
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/base/RuleResult.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.base
2 |
3 | import kotlinx.serialization.Serializable
4 | import kotlinx.serialization.encodeToString
5 | import kotlinx.serialization.json.Json
6 |
7 | /**
8 | * We need to find a better way to represent the result of a rule.
9 | * Since we need to limit tokens in the result, we use a string to represent the result.
10 | */
11 | @Serializable
12 | data class RuleResult(
13 | val name: String,
14 | val rule: String,
15 | val success: Boolean,
16 | val value: String = "",
17 | ) {
18 | override fun toString(): String {
19 | return Json.encodeToString(this)
20 | }
21 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/base/verifier/LlmRuleVerifier.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.base.verifier
2 |
3 | /**
4 | * Use LLM to verify the rule
5 | */
6 | interface LlmRuleVerifier {
7 | fun check(prompt: String, input: String): Boolean
8 | }
9 |
10 | class FakeRuleVerifier : LlmRuleVerifier {
11 | override fun check(prompt: String, input: String): Boolean {
12 | return true
13 | }
14 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/element/Element.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.element
2 |
3 | interface Element
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/element/FoundationElement.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.element
2 |
3 | import chapi.domain.core.CodeDataStruct
4 | import org.archguard.spec.lang.foundation.declaration.LayeredDefine
5 |
6 | class FoundationElement(
7 | val projectName: String,
8 | val ds: List,
9 | /**
10 | * we delay to fill this field until we have all the information we need
11 | * to fill it. like the layer name, the layer type, etc.
12 | */
13 | var layeredDefines: List = listOf(),
14 | ) : Element {
15 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/element/RestApiElement.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.element
2 |
3 | import kotlinx.serialization.json.JsonObject
4 |
5 | data class RestApiElement(
6 | val uri: String,
7 | val httpAction: String,
8 | val statusCodes: List,
9 | val request: JsonObject? = null,
10 | val response: List = listOf(),
11 | ) : Element {
12 | override fun toString(): String {
13 | return "RestApi(uri='$uri', action='$httpAction', statusCodes=$statusCodes, request=$request, response=$response)"
14 | }
15 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/execute/DomainModelScanner.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.execute
2 |
3 | import chapi.domain.core.CodeDataStruct
4 |
5 | interface DomainModelScanner {
6 | fun scan(): List
7 | fun toUml(ds: List): String
8 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/ArchitectureSpec.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang
2 |
3 | import org.archguard.spec.lang.architecture.SystemDeclaration
4 | import org.archguard.spec.lang.base.RuleSpec
5 | import org.archguard.spec.lang.base.Spec
6 |
7 | @SpecDsl
8 | class ArchitectureSpec : RuleSpec {
9 | override fun default(): Spec = defaultSpec()
10 |
11 | fun system(systemName: String, block: SystemDeclaration.() -> Unit): SystemDeclaration {
12 | val system = SystemDeclaration(systemName)
13 | system.block()
14 | return system
15 | }
16 |
17 | companion object {
18 | fun defaultSpec(): ArchitectureSpec {
19 | return architecture {
20 | system("TicketBooking") {
21 | connection("Reservation" to "Ticket")
22 | }
23 | }
24 | }
25 | }
26 | }
27 |
28 | /**
29 | * Architecture DSL is a useless DSL for architecture specification.
30 | */
31 | fun architecture(function: ArchitectureSpec.() -> Unit): ArchitectureSpec {
32 | val spec = ArchitectureSpec()
33 | spec.function()
34 | return spec
35 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/ComposableSpec.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang
2 |
3 | import kotlinx.serialization.Serializable
4 | import org.archguard.spec.base.RuleResult
5 | import org.archguard.spec.lang.base.Spec
6 |
7 | @Serializable
8 | data class Scenario(val name: String, val description: String)
9 |
10 | @SpecDsl
11 | class ComposableSpec : Spec {
12 | override fun exec(element: Scenario): List = listOf()
13 |
14 | override fun default(): Spec {
15 | return defaultSpec()
16 | }
17 |
18 | companion object {
19 | fun defaultSpec(): ComposableSpec {
20 | return composable {
21 | channels {
22 |
23 | }
24 | integrations { }
25 | business { }
26 | records { }
27 | capabilities { }
28 | }
29 | }
30 | }
31 |
32 | fun channels(function: ChannelsDeclaration.() -> Unit): ChannelsDeclaration {
33 | val channelsDeclaration = ChannelsDeclaration()
34 | channelsDeclaration.function()
35 | return channelsDeclaration
36 | }
37 |
38 | inner class ChannelsDeclaration() {
39 |
40 | }
41 |
42 | fun integrations(function: () -> Unit) {
43 |
44 | }
45 |
46 | fun business(function: () -> Unit) {
47 |
48 | }
49 |
50 | fun records(function: () -> Unit) {
51 |
52 | }
53 |
54 | fun capabilities(function: () -> Unit) {
55 |
56 | }
57 | }
58 |
59 | /**
60 | * Composable DSL is an EA (enterprise architecture) specification language with a focus on composable architecture.
61 | * It is used to describe the architecture of a software system.
62 | */
63 | fun composable(function: ComposableSpec.() -> Unit): ComposableSpec {
64 | val spec = ComposableSpec()
65 | spec.function()
66 | return spec
67 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/DomainSpec.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang
2 |
3 | import org.archguard.spec.lang.base.Spec
4 | import org.archguard.spec.lang.domain.declaration.ContextMapDeclaration
5 |
6 | @SpecDsl
7 | class DomainSpec : Spec {
8 | fun context_map(name: String, block: ContextMapDeclaration.() -> Unit): ContextMapDeclaration {
9 | val contextMapDeclaration = ContextMapDeclaration(name)
10 | contextMapDeclaration.block()
11 | return contextMapDeclaration
12 | }
13 |
14 | override fun default(): Spec = defaultSpec()
15 |
16 | companion object {
17 | fun defaultSpec(): DomainSpec =
18 | domain {
19 | context_map("TicketBooking") {
20 | context("Reservation") {}
21 | context("Ticket") {}
22 |
23 | mapping {
24 | context("Reservation") dependedOn context("Ticket")
25 | context("Reservation") dependedOn context("Movie")
26 | }
27 | }
28 | }
29 | }
30 | }
31 |
32 | /**
33 | * Domain DSL is a DDD style's concept map.
34 | */
35 | fun domain(init: DomainSpec.() -> Unit): DomainSpec {
36 | val spec = DomainSpec()
37 | spec.init()
38 | return spec
39 | }
40 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/SpecDsl.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang
2 |
3 | @DslMarker
4 | annotation class SpecDsl
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/architecture/ArchitectureDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.architecture
2 |
3 | import org.archguard.spec.lang.base.BaseDeclaration
4 |
5 | class ConnectionDeclaration(val source: String, val target: String) : BaseDeclaration
6 |
7 | class SystemDeclaration(val name: String) : BaseDeclaration {
8 | fun component(componentName: String, function: ComponentDeclaration.() -> Unit): ComponentDeclaration {
9 | val component = ComponentDeclaration(componentName)
10 | component.function()
11 | return component
12 | }
13 |
14 | fun connection(pair: Pair, function: ConnectionDeclaration.() -> Unit?): ConnectionDeclaration {
15 | val connection = ConnectionDeclaration(pair.first, pair.second)
16 | connection.function()
17 | return connection
18 | }
19 |
20 | fun connection(pair: Pair): ConnectionDeclaration {
21 | return ConnectionDeclaration(pair.first, pair.second)
22 | }
23 |
24 | }
25 |
26 | class ComponentDeclaration(val name: String) : BaseDeclaration {
27 | fun module(moduleName: String, function: ModuleDeclaration.() -> Unit): ModuleDeclaration {
28 | val module = ModuleDeclaration(moduleName)
29 | module.function()
30 | return module
31 | }
32 | }
33 |
34 | class ModuleDeclaration(val name: String) : BaseDeclaration
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/base/BaseDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.base
2 |
3 | import org.archguard.spec.base.Rule
4 |
5 | interface BaseDeclaration {
6 | fun rules(element: T): List> {
7 | return listOf()
8 | }
9 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/base/PatternWithExampleRule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.base
2 |
3 | import org.archguard.spec.base.Rule
4 | import org.archguard.spec.base.RuleResult
5 |
6 | interface PatternWithExampleRule : Rule {
7 | fun pattern(regex: String)
8 | fun example(sample: String)
9 | override fun exec(input: T): List {
10 | return listOf()
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/base/Spec.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.base
2 |
3 | import org.archguard.spec.base.RuleResult
4 | import org.archguard.spec.base.verifier.LlmRuleVerifier
5 |
6 | interface Spec {
7 | fun setVerifier(ruleVerifier: LlmRuleVerifier) {}
8 | fun exec(element: T): List = listOf()
9 | fun default(): Spec
10 | fun example(): String = ""
11 | }
12 |
13 | interface RuleSpec : Spec {
14 | override fun setVerifier(ruleVerifier: LlmRuleVerifier) {}
15 | override fun exec(element: T): List = listOf()
16 | override fun default(): Spec
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/caseflow/CaseFlowModel.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.caseflow
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class CaseFlow(
7 | val name: String,
8 | val defaultActor: String = "User",
9 | val activities: List,
10 | val stories: List
11 | )
12 |
13 | @Serializable
14 | data class Activity(
15 | val name: String,
16 | val tasks: List
17 | )
18 |
19 | @Serializable
20 | data class Task(
21 | val name: String,
22 | var actor: String? = null,
23 | var storyNames: List = listOf()
24 | )
25 |
26 | @Serializable
27 | data class Story(
28 | val name: String,
29 | val scenes: List
30 | )
31 |
32 | @Serializable
33 | data class Scene(
34 | val name: String,
35 | val steps: List
36 | )
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/caseflow/declaration/SceneDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.caseflow.declaration
2 |
3 | import org.archguard.spec.lang.caseflow.Scene
4 |
5 | enum class StepType(val value: String) {
6 | GIVEN("Given"),
7 | WHEN("When"),
8 | THEN("Then"),
9 | AND("And");
10 | }
11 |
12 | class SceneDeclaration(val description: String) {
13 | val steps: MutableList = mutableListOf()
14 |
15 | fun Given(description: String) {
16 | steps.add(NamedStep(StepType.GIVEN, description))
17 | }
18 |
19 | fun And(description: String) {
20 | steps.add(NamedStep(StepType.AND, description))
21 | }
22 |
23 | fun When(description: String) {
24 | steps.add(NamedStep(StepType.WHEN, description))
25 | }
26 |
27 | fun Then(description: String) {
28 | steps.add(NamedStep(StepType.THEN, description))
29 | }
30 |
31 | fun toModel(): Scene {
32 | return Scene(description, steps.map { it.description })
33 | }
34 |
35 | override fun toString(): String {
36 | return """
37 | | scene("$description") {
38 | |${steps.joinToString("\n") { " ${it.type.value}(\"${it.description}\")".replace("\n", "\n") }}
39 | | }
40 | """.trimMargin()
41 | }
42 |
43 | inner class NamedStep(val type: StepType, val description: String)
44 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/caseflow/declaration/StoryDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.caseflow.declaration
2 |
3 | import org.archguard.spec.lang.caseflow.Story
4 |
5 | class StoryDeclaration(val name: String) {
6 | private val sceneDeclarations: MutableList = mutableListOf()
7 |
8 | fun scene(scenario: String, function: SceneDeclaration.() -> Unit): SceneDeclaration {
9 | val sceneDeclaration = SceneDeclaration(scenario)
10 | sceneDeclaration.function()
11 | sceneDeclarations.add(sceneDeclaration)
12 | return sceneDeclaration
13 | }
14 |
15 | fun toModel(): Story {
16 | return Story(name, sceneDeclarations.map { it.toModel() })
17 | }
18 |
19 | override fun toString(): String {
20 | return """
21 | |story("$name") {
22 | |${sceneDeclarations.joinToString("\n") { " ${it.toString().replace("\n", "\n ")}" }}
23 | | }
24 | """.trimMargin()
25 | }
26 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/concept/Behavior.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.concept
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class Behavior(val action: String, val description: String = "")
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/concept/CodeBlock.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.concept
2 |
3 | typealias CodeBlock = Any
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/concept/declaration/ConceptDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.concept.declaration
2 |
3 | import org.archguard.spec.lang.concept.Behavior
4 |
5 | /**
6 | * Concept is a class abstraction for a concept, will be used to generate code.
7 | */
8 | class ConceptDeclaration(private val className: String, private val packageName: String = "") {
9 | val formatBehaviors = mutableListOf()
10 |
11 | /**
12 | * Define a list of [Behavior], for example:
13 | *
14 | * ```kotlin
15 | * behaviors = listOf("View Menu", "Place Order", "Pay", "View Order Status", "View Order History")
16 | * ```
17 | */
18 | var behaviors: List = emptyList()
19 |
20 | /**
21 | * behavior is a synonym of usecase, same to [ConceptDeclaration.usecase]
22 | * can define with description or empty
23 | * ```kotlin
24 | * behavior("Place Order", "Place an order for a coffee")
25 | * behavior("Place Order")
26 | * ```
27 | */
28 | fun behavior(action: String, description: String = "") {
29 | formatBehaviors.add(Behavior(action, description))
30 | }
31 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/domain/MappingDefine.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.domain
2 |
3 | class MappingDefine {}
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/domain/declaration/AggregateDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.domain.declaration
2 |
3 | class AggregateDeclaration(name: String) {}
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/domain/declaration/ContextDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.domain.declaration
2 |
3 | class ContextDeclaration(val name: String) {
4 | val relations: MutableList> = mutableListOf()
5 | fun aggregate(name: String, function: AggregateDeclaration.() -> Unit): AggregateDeclaration {
6 | val aggregateDeclaration = AggregateDeclaration(name)
7 | aggregateDeclaration.function()
8 | return aggregateDeclaration
9 | }
10 |
11 | infix fun dependedOn(targetContextDeclaration: ContextDeclaration) {
12 | relations += this to targetContextDeclaration
13 | }
14 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/domain/declaration/ContextMapDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.domain.declaration
2 |
3 | import org.archguard.spec.lang.domain.MappingDefine
4 |
5 | class ContextMapDeclaration(val name: String) {
6 | fun context(name: String, function: ContextDeclaration.() -> Unit): ContextDeclaration {
7 | val contextDeclaration = ContextDeclaration(name)
8 | contextDeclaration.function()
9 | return contextDeclaration
10 | }
11 |
12 | fun context(name: String): ContextDeclaration = ContextDeclaration(name)
13 |
14 | fun mapping(block: MappingDefine.() -> Unit): MappingDefine {
15 | val mapping = MappingDefine()
16 | mapping.block()
17 | return mapping
18 | }
19 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/foundation/declaration/LayeredDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.foundation.declaration
2 |
3 | import org.archguard.spec.base.Rule
4 | import org.archguard.spec.lang.base.BaseDeclaration
5 | import org.archguard.spec.lang.foundation.rule.DependencyRule
6 | import org.archguard.spec.element.FoundationElement
7 | import org.jetbrains.annotations.TestOnly
8 |
9 | class LayeredDeclaration : BaseDeclaration {
10 | private val dependencyRules = mutableListOf()
11 | private val layerRules = mutableListOf()
12 |
13 | fun layer(name: String, function: LayeredDefine.() -> Unit): LayeredDefine {
14 | val rule = LayeredDefine(name)
15 | rule.function()
16 | layerRules.add(rule)
17 | return rule
18 | }
19 |
20 | fun dependency(function: DependencyRule.() -> Unit): DependencyRule {
21 | val rule = DependencyRule()
22 | rule.function()
23 | dependencyRules.add(rule)
24 | return rule
25 | }
26 |
27 | override fun rules(element: FoundationElement): List> {
28 | return layerRules + dependencyRules
29 | }
30 |
31 | override fun toString(): String {
32 | val indent = " "
33 | val layered = layerRules.joinToString(separator = "\n").lines().joinToString(separator = "\n") { "$indent$it" }
34 | val deps =
35 | dependencyRules.joinToString(separator = "\n").lines().joinToString(separator = "\n") { "$indent$indent$it" }
36 |
37 | val insider = """$layered
38 | dependency {
39 | $deps
40 | }"""
41 |
42 | return """layered {
43 | $insider
44 | }"""
45 | }
46 | }
47 |
48 | @TestOnly
49 | fun layered_t(function: LayeredDeclaration.() -> Unit): LayeredDeclaration {
50 | val declaration = LayeredDeclaration()
51 | declaration.function()
52 | return declaration
53 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/foundation/declaration/NamingDeclaration.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.foundation.declaration
2 |
3 | import org.archguard.spec.base.Rule
4 | import org.archguard.spec.lang.base.BaseDeclaration
5 | import org.archguard.spec.lang.foundation.rule.NamingStyleRule
6 | import org.archguard.spec.element.FoundationElement
7 | import org.jetbrains.annotations.TestOnly
8 |
9 | enum class NamingTarget {
10 | Package,
11 | Class,
12 | Function,
13 | }
14 |
15 | class NamingDeclaration : BaseDeclaration {
16 | val rules: MutableList> = mutableListOf()
17 |
18 | fun class_level(function: NamingStyleRule.() -> Unit): NamingStyleRule {
19 | val rule = NamingStyleRule(NamingTarget.Class)
20 | rule.function()
21 |
22 | rules.add(rule)
23 | return rule
24 | }
25 |
26 | fun function_level(function: NamingStyleRule.() -> Unit): NamingStyleRule {
27 | val rule = NamingStyleRule(NamingTarget.Function)
28 | rule.function()
29 |
30 | rules.add(rule)
31 | return rule
32 | }
33 |
34 | override fun rules(element: FoundationElement): List> {
35 | return rules
36 | }
37 |
38 | override fun toString(): String {
39 | val rules = rules.joinToString(separator = "\n").lines().joinToString(separator = "\n") { " $it" }
40 | return """naming {
41 | $rules
42 | }"""
43 | }
44 | }
45 |
46 | @TestOnly
47 | fun naming_t(function: NamingDeclaration.() -> Unit): NamingDeclaration {
48 | val declaration = NamingDeclaration()
49 | declaration.function()
50 | return declaration
51 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/foundation/expression/NamingRuleExpression.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.foundation.expression
2 |
3 | import org.archguard.spec.lang.foundation.rule.NamingRule
4 | import java.io.Serializable
5 |
6 | typealias NamingExpression = NamingRule.() -> Serializable?
7 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/matcher/Compare.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.matcher
2 |
3 | enum class CompareType {
4 | ENDS_WITH,
5 | STARTS_WITH,
6 | CONTAINS
7 | }
8 |
9 | data class DelayCompare(
10 | var left: String,
11 | val compareType: CompareType,
12 | val right: List,
13 | var equal: Boolean = true,
14 | ) {
15 | fun compare(): Boolean {
16 | val result = when (compareType) {
17 | CompareType.ENDS_WITH -> {
18 | right.any { left.endsWith(it) }
19 | }
20 |
21 | CompareType.STARTS_WITH -> {
22 | right.any { left.startsWith(it) }
23 | }
24 |
25 | CompareType.CONTAINS -> {
26 | right.any { left.contains(it) }
27 | }
28 | }
29 |
30 | return if (equal) result else !result
31 | }
32 |
33 | override fun toString(): String {
34 | val infix = when(equal) {
35 | true -> "shouldBe"
36 | false -> "shouldNotBe"
37 | }
38 |
39 | val compare = when(compareType) {
40 | CompareType.ENDS_WITH -> "endsWith"
41 | CompareType.STARTS_WITH -> "startsWith"
42 | CompareType.CONTAINS -> "contains"
43 | }
44 |
45 | return """$left $infix $compare("${right.joinToString("\", \"")}")"""
46 | }
47 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/matcher/Matcher.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.matcher
2 |
3 | import java.io.Serializable
4 |
5 | infix fun T.shouldBe(expected: DelayCompare?): Serializable? {
6 | if (expected != null) {
7 | expected.equal = true
8 | }
9 |
10 | return ""
11 | }
12 |
13 | infix fun T.shouldNotBe(any: DelayCompare?): Serializable? {
14 | if (any != null) {
15 | any.equal = false
16 | }
17 |
18 | return ""
19 | }
20 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/restapi/ApiAtomicRule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.restapi
2 |
3 | import org.archguard.spec.base.Rule
4 | import org.archguard.spec.base.RuleResult
5 | import org.archguard.spec.element.RestApiElement
6 |
7 | abstract class ApiAtomicRule(override val actionName: String, open var rule: String) : Rule {
8 | abstract override fun exec(input: RestApiElement): List
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/restapi/ApiLlmVerifyRule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.restapi
2 |
3 | import org.archguard.spec.base.LlmRule
4 | import org.archguard.spec.base.verifier.LlmRuleVerifier
5 | import org.archguard.spec.base.RuleResult
6 | import org.archguard.spec.element.RestApiElement
7 |
8 | abstract class ApiLlmVerifyRule(
9 | override val actionName: String,
10 | override var rule: String,
11 | open var ruleVerifier: LlmRuleVerifier,
12 | ) : LlmRule, ApiAtomicRule(actionName, rule) {
13 | override fun exec(input: RestApiElement): List = listOf()
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/restapi/rule/HttpActionRule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.restapi.rule
2 |
3 | import org.archguard.spec.base.RuleResult
4 | import org.archguard.spec.lang.restapi.ApiAtomicRule
5 | import org.archguard.spec.element.RestApiElement
6 |
7 | class HttpActionRule(private val actions: List) : ApiAtomicRule("http-action", "supported http actions: ${actions.joinToString(", ")}") {
8 | override fun exec(input: RestApiElement): List {
9 | return listOf(RuleResult(this.actionName, this.rule, actions.contains(input.httpAction)))
10 | }
11 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/restapi/rule/MiscRule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.restapi.rule
2 |
3 | import org.archguard.spec.base.verifier.LlmRuleVerifier
4 | import org.archguard.spec.lang.restapi.ApiLlmVerifyRule
5 | import org.archguard.spec.base.RuleResult
6 | import org.archguard.spec.element.RestApiElement
7 |
8 | class MiscRule(private val ruleContent: String, override var ruleVerifier: LlmRuleVerifier) :
9 | ApiLlmVerifyRule("security", ruleContent, ruleVerifier) {
10 | override fun exec(input: RestApiElement): List {
11 | return listOf(RuleResult(this.actionName, this.rule, ruleVerifier.check(ruleContent, input.toString())))
12 | }
13 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/restapi/rule/SecurityRule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.restapi.rule
2 |
3 | import org.archguard.spec.base.verifier.LlmRuleVerifier
4 | import org.archguard.spec.lang.restapi.ApiLlmVerifyRule
5 | import org.archguard.spec.base.RuleResult
6 | import org.archguard.spec.element.RestApiElement
7 |
8 | class SecurityRule(private val ruleContent: String, override var ruleVerifier: LlmRuleVerifier) :
9 | ApiLlmVerifyRule("security", ruleContent, ruleVerifier) {
10 | override fun exec(input: RestApiElement): List {
11 | return listOf(RuleResult(this.actionName, this.rule, ruleVerifier.check(ruleContent, input.toString())))
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/restapi/rule/StatusCodeRule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.restapi.rule
2 |
3 | import org.archguard.spec.base.RuleResult
4 | import org.archguard.spec.lang.restapi.ApiAtomicRule
5 | import org.archguard.spec.element.RestApiElement
6 |
7 | class StatusCodeRule(private val codes: List) : ApiAtomicRule("status-code", "supported codes: ${codes.joinToString(", ")}") {
8 | override fun exec(input: RestApiElement): List {
9 | if (input.statusCodes.isEmpty()) {
10 | return listOf(RuleResult(this.actionName, this.rule, false))
11 | }
12 |
13 | val statusCode = input.statusCodes
14 |
15 | val isEqual = if (statusCode.size == 1) {
16 | statusCode[0] == codes[0]
17 | } else {
18 | statusCode.containsAll(codes)
19 | }
20 |
21 | return listOf(RuleResult(this.actionName, this.rule, isEqual))
22 | }
23 | }
--------------------------------------------------------------------------------
/spec-lang/src/main/kotlin/org/archguard/spec/lang/restapi/rule/UriConstructionRule.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.restapi.rule
2 |
3 | import org.archguard.spec.lang.base.PatternWithExampleRule
4 | import org.archguard.spec.base.RuleResult
5 | import org.archguard.spec.lang.restapi.ApiAtomicRule
6 | import org.archguard.spec.element.RestApiElement
7 |
8 | class UriConstructionRule : ApiAtomicRule("uri-construction", "uri construction regex: //TODO"),
9 | PatternWithExampleRule {
10 | private var ruleRegex: Regex? = null
11 | private var sample = ""
12 |
13 | override fun pattern(regex: String) {
14 | this.ruleRegex = Regex(regex)
15 | this.rule = "uri construction regex: $regex"
16 | }
17 |
18 | override fun example(sample: String) {
19 | this.sample = sample
20 | }
21 |
22 | override fun exec(input: RestApiElement): List {
23 | if (ruleRegex != null) {
24 | val matchResult = ruleRegex!!.find(input.uri)
25 | return listOf(RuleResult(this.actionName, sample, matchResult != null))
26 | }
27 |
28 | return listOf(RuleResult(this.actionName, sample, false))
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/architecture/action/IOActionTypeTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.architecture.action
2 |
3 | import org.junit.jupiter.api.Assertions.*
4 | import org.junit.jupiter.api.Test
5 |
6 | class IOActionTypeTest {
7 | @Test
8 | fun should_get_class_by_value_of() {
9 | assertEquals(IOActionType.CREATE_DIRECTORY, IOActionType.from("CREATE_DIRECTORY"))
10 | assertEquals(IOActionType.CREATE_FILE, IOActionType.from("CREATE_FILE"))
11 | assertEquals(IOActionType.CREATE_PACKAGE, IOActionType.from("CREATE_PACKAGE"))
12 | assertEquals(IOActionType.CREATE_CLASS, IOActionType.from("CREATE_CLASS"))
13 | assertEquals(IOActionType.CREATE_INTERFACE, IOActionType.from("CREATE_INTERFACE"))
14 | assertEquals(IOActionType.CREATE_ENUM, IOActionType.from("CREATE_ENUM"))
15 |
16 | assertEquals(IOActionType.UNKNOWN, IOActionType.from("NOT_EXIST"))
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/spec/lang/ArchitectureSpecTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang
2 |
3 | import org.junit.jupiter.api.Assertions.*
4 | import org.junit.jupiter.api.Test
5 |
6 | class ArchitectureSpecTest {
7 | @Test
8 | fun `should return empty result when no rule is defined`() {
9 | val spec = architecture {
10 | system("MySystem") {
11 | component("MyComponent") {
12 | module("") {}
13 | }
14 |
15 | connection("WebServer" to "Database")
16 | }
17 | }
18 |
19 | val result = spec.exec("")
20 |
21 | assertTrue(result.isEmpty())
22 | }
23 | }
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/spec/lang/ComposableSpecTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang
2 |
3 | import org.junit.jupiter.api.Assertions.*
4 |
5 | class ComposableSpecTest {
6 | @org.junit.jupiter.api.Test
7 | fun testDefaultSpec() {
8 | val spec = ComposableSpec().default()
9 | assertEquals(0, spec.exec(Scenario("test", "test")).size)
10 | }
11 | }
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/spec/lang/ConceptSpecTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang
2 |
3 | import io.kotest.matchers.shouldBe
4 | import org.junit.jupiter.api.Assertions.*
5 | import org.junit.jupiter.api.Test
6 |
7 | class ConceptSpecTest {
8 | @Test
9 | fun should_equal_when_had_same_spec() {
10 | val spec = ConceptSpec.defaultSpec()
11 | assertEquals(ConceptSpec.defaultSpec().toString(), spec.toString())
12 | }
13 |
14 | @Test
15 | fun should_ident_concept_from_spec() {
16 | val spec = concepts {
17 | val customer = Concept("Customer") {
18 | behavior("Place Order", "Place an order for a coffee")
19 | behaviors = listOf("View Menu", "Place Order", "Pay", "View Order Status", "View Order History")
20 | }
21 |
22 | val barista = Concept("Barista") {
23 | behavior("Make Coffee")
24 | }
25 |
26 | Concept("cart")
27 |
28 | relations {
29 | customer["Place Order"] perform barista
30 | customer["View Menu"] perform barista
31 | customer["View Order History"] perform barista
32 |
33 | customer["Custom something"].perform(barista)
34 | }
35 | }
36 |
37 | spec.concepts.size shouldBe 3
38 | val customer = spec.concepts[0]
39 | customer.conceptName shouldBe "Customer"
40 | customer.behaviors.size shouldBe 4
41 | println(customer.toString())
42 |
43 | val secondConcept = spec.concepts[1]
44 | secondConcept.conceptName shouldBe "Barista"
45 | println(secondConcept.toString())
46 | }
47 | }
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/spec/lang/DomainSpecTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang
2 |
3 | import org.junit.jupiter.api.Test
4 |
5 | class DomainSpecTest {
6 | private val governance = domain {
7 | context_map("TicketBooking") {
8 | context("Reservation") {}
9 | context("Ticket") {}
10 |
11 | mapping {
12 | context("Reservation") dependedOn context("Ticket")
13 | context("Reservation") dependedOn context("Movie")
14 | }
15 | }
16 | }
17 |
18 | @Test
19 | fun testContextMap() {
20 | governance.exec("")
21 | }
22 | }
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/spec/lang/RestRestApiSpecTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang
2 |
3 | import org.archguard.spec.base.verifier.FakeRuleVerifier
4 | import org.archguard.spec.element.RestApiElement
5 | import org.junit.jupiter.api.Test
6 |
7 | class RestRestApiSpecTest {
8 | private val governance = rest_api {
9 | uri_construction {
10 | pattern("/api\\/[a-zA-Z0-9]+\\/v[0-9]+\\/[a-zA-Z0-9\\/\\-]+")
11 | example("/api/petstore/v1/pets/dogs")
12 | }
13 |
14 | http_action("GET", "POST", "PUT", "DELETE")
15 | status_code(200, 201, 202, 204, 400, 401, 403, 404, 500, 502, 503, 504)
16 |
17 | security(
18 | """
19 | Token Based Authentication (Recommended) Ideally, microservices should be stateless so the service instances can be scaled out easily and the client requests can be routed to multiple independent service providers. A token based authentication mechanism should be used instead of session based authentication
20 | """.trimIndent()
21 | )
22 |
23 | misc("""""")
24 | }
25 |
26 | @Test
27 | fun spec_checking() {
28 |
29 | val restApi = RestApiElement("/api/petstore/v1/pets/dogs", "GET", listOf(200, 500))
30 | governance.setVerifier(FakeRuleVerifier())
31 | governance.exec(restApi)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/spec/lang/foundation/declaration/LayeredDefineTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.foundation.declaration
2 |
3 | import org.archguard.spec.lang.matcher.shouldBe
4 | import org.junit.jupiter.api.Assertions.*
5 | import org.junit.jupiter.api.Test
6 |
7 | class LayeredDefineTest {
8 | @Test
9 | fun should_get_origin_text_in_string() {
10 | val declaration = layered_t("interface") {
11 | pattern(".*\\.apis") { name shouldBe endsWith("Controller") }
12 | }
13 |
14 | assertEquals(
15 | declaration.toString(), """
16 | layer("interface") {
17 | pattern(".*\.apis") { name shouldBe endsWith("Controller") }
18 | }
19 | """.trimIndent()
20 | )
21 | }
22 | }
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/spec/lang/foundation/rule/DependencyRuleTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.foundation.rule
2 |
3 | import org.junit.jupiter.api.Test
4 | import kotlin.test.assertEquals
5 |
6 | class DependencyRuleTest {
7 | @Test
8 | fun should_return_correct_to_string_for_dependency() {
9 | val decl = dependency_t {
10 | "interface" dependedOn "application"
11 | }
12 |
13 | assertEquals(decl.toString(), "\"interface\" dependedOn \"application\"")
14 | }
15 |
16 | @Test
17 | fun should_return_correct_to_string_for_dependency_with_multiple_deps() {
18 | val decl = dependency_t {
19 | "interface" dependedOn "application"
20 | "interface" dependedOn "domain"
21 | }
22 |
23 | assertEquals(
24 | decl.toString(),
25 | """"interface" dependedOn "application"
26 | "interface" dependedOn "domain""""
27 | )
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/spec/lang/foundation/rule/ProjectNameRuleTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.foundation.rule
2 |
3 | import org.archguard.spec.element.FoundationElement
4 | import org.junit.jupiter.api.Assertions.*
5 | import org.junit.jupiter.api.Test
6 |
7 | class ProjectNameRuleTest {
8 | @Test
9 | fun should_return_true_when_project_name_correct() {
10 | val projectNameRule = project_name_t {
11 | pattern("^([a-z0-9-]+)-([a-z0-9-]+)-([a-z0-9-]+)(-common)?\$")
12 | example("system1-servicecenter1-microservice1")
13 | }
14 |
15 | val exec = projectNameRule.exec(FoundationElement("ms-sc-auth", listOf()))
16 | assertEquals(1, exec.size)
17 | assertEquals(true, exec[0].success)
18 | }
19 |
20 | @Test
21 | fun should_return_false_when_project_name_incorrect() {
22 | val projectNameRule = project_name_t {
23 | pattern("^([a-z0-9-]+)-([a-z0-9-]+)-([a-z0-9-]+)(-common)?\$")
24 | example("system1-servicecenter1-microservice1")
25 | }
26 |
27 | val exec = projectNameRule.exec(FoundationElement("ms-sc", listOf()))
28 | assertEquals(1, exec.size)
29 | assertEquals(false, exec[0].success)
30 | }
31 |
32 | @Test
33 | fun should_correct_generate_string() {
34 | val projectNameRule = project_name_t {
35 | pattern("^([a-z0-9-]+)-([a-z0-9-]+)-([a-z0-9-]+)(-common)?\$")
36 | example("system1-servicecenter1-microservice1")
37 | }
38 |
39 | assertEquals(
40 | projectNameRule.toString(),
41 | """
42 | project_name {
43 | pattern("^([a-z0-9-]+)-([a-z0-9-]+)-([a-z0-9-]+)(-common)?${'$'}")
44 | example("system1-servicecenter1-microservice1")
45 | }
46 | """.trimIndent()
47 | )
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/spec-lang/src/test/kotlin/org/archguard/spec/lang/matcher/DelayCompareTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.lang.matcher
2 |
3 | import org.junit.jupiter.api.Assertions.*
4 | import org.junit.jupiter.api.Test
5 |
6 | class DelayCompareTest {
7 | @Test
8 | fun should_get_correct_to_string() {
9 | val delayCompare = DelayCompare("test", CompareType.ENDS_WITH, listOf("t"))
10 | assertEquals("test shouldBe endsWith(\"t\")", delayCompare.toString())
11 | }
12 |
13 | @Test
14 | fun should_get_multiple_string_for_array() {
15 | val delayCompare = DelayCompare("test", CompareType.STARTS_WITH, listOf("t", "s"))
16 | assertEquals("test shouldBe startsWith(\"t\", \"s\")", delayCompare.toString())
17 | }
18 | }
--------------------------------------------------------------------------------
/spec-partitioner/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(projects.specLang)
9 | implementation(projects.specLang)
10 | implementation(projects.llmCore)
11 | implementation(projects.llmSemantic)
12 |
13 | implementation(libs.serialization.json)
14 | implementation(libs.kotlin.stdlib)
15 | implementation(libs.bundles.markdown)
16 |
17 | testImplementation(libs.bundles.test)
18 | testRuntimeOnly(libs.test.junit.engine)
19 | }
20 |
--------------------------------------------------------------------------------
/spec-partitioner/src/main/kotlin/org/archguard/spec/markdown/CodeBlockFilter.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.markdown
2 |
3 | import org.commonmark.node.AbstractVisitor
4 | import org.commonmark.node.FencedCodeBlock
5 |
6 | internal class CodeFilter(private val lang: String? = null) : AbstractVisitor() {
7 | var code = listOf()
8 |
9 | override fun visit(fencedCodeBlock: FencedCodeBlock?) {
10 | if (fencedCodeBlock?.literal != null) {
11 | if (lang == null) {
12 | this.code += fencedCodeBlock.literal
13 | } else {
14 | if (fencedCodeBlock.info == lang) {
15 | this.code += fencedCodeBlock.literal
16 | }
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/spec-partitioner/src/main/kotlin/org/archguard/spec/markdown/TableToMapVisitor.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.markdown
2 |
3 | import org.commonmark.ext.gfm.tables.TableCell
4 | import org.commonmark.ext.gfm.tables.TableHead
5 | import org.commonmark.ext.gfm.tables.TableRow
6 | import org.commonmark.node.AbstractVisitor
7 | import org.commonmark.node.CustomBlock
8 | import org.commonmark.node.CustomNode
9 | import org.commonmark.node.Text
10 |
11 | internal class TableToMapVisitor : AbstractVisitor() {
12 | val headers = mutableMapOf>()
13 | private var isBeforeHeadLine = true
14 | private var headerIndex = 0
15 |
16 | override fun visit(customNode: CustomNode?) {
17 | super.visit(customNode)
18 |
19 | when (customNode) {
20 | is TableHead -> {
21 | isBeforeHeadLine = false
22 | }
23 |
24 | is TableCell -> {
25 | if (isBeforeHeadLine) {
26 | val header = (customNode.firstChild as Text).literal
27 | headers[header] = listOf()
28 | } else {
29 | val header = headers.keys.elementAt(headerIndex)
30 | headers[header] = headers[header]!! + (customNode.firstChild as Text).literal
31 | }
32 |
33 | headerIndex++
34 | }
35 |
36 | is TableRow -> {
37 | headerIndex = 0
38 | }
39 | }
40 | }
41 |
42 | override fun visit(customBlock: CustomBlock?) {
43 | super.visit(customBlock)
44 | }
45 | }
--------------------------------------------------------------------------------
/spec-partitioner/src/main/kotlin/org/archguard/spec/partition/ApiPartitioner.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.partition
2 |
3 | import org.archguard.comate.smart.Semantic
4 | import org.archguard.spec.base.Rule
5 | import org.archguard.spec.lang.restapi.ApiAtomicRule
6 | import org.archguard.spec.lang.restapi.rule.*
7 |
8 | // todo: is for checking the rule type
9 | enum class ApiRuleType(rule: Class) {
10 | HTTP_ACTION(HttpActionRule::class.java),
11 | MISC(MiscRule::class.java),
12 | SECURITY(SecurityRule::class.java),
13 | STATUS_CODE(StatusCodeRule::class.java),
14 | URI_CONSTRUCTION(UriConstructionRule::class.java)
15 | }
16 |
17 | val apiEmbeddingMap: Map
18 | get() {
19 | val map = mutableMapOf()
20 | val uris = listOf("URI Construction", "Construction")
21 | val statusCode = listOf("HTTP response status codes", "Status Code", "Request/Response Status Code")
22 | val httpMethods = listOf("HTTP Methods", "HTTP Method", "Method")
23 | val security = listOf("Security", "Authentication", "Authorization")
24 | val misc = listOf("Miscellaneous", "Misc")
25 |
26 | val semantic = Semantic.create()
27 | uris.forEach {
28 | map[semantic.embed(it)] = ApiRuleType.URI_CONSTRUCTION
29 | }
30 | statusCode.forEach {
31 | map[semantic.embed(it)] = ApiRuleType.STATUS_CODE
32 | }
33 | httpMethods.forEach {
34 | map[semantic.embed(it)] = ApiRuleType.HTTP_ACTION
35 | }
36 | security.forEach {
37 | map[semantic.embed(it)] = ApiRuleType.SECURITY
38 | }
39 | misc.forEach {
40 | map[semantic.embed(it)] = ApiRuleType.MISC
41 | }
42 |
43 | return map
44 | }
45 |
46 | class ApiPartitioner : Partitioner {
47 | override fun partition(): List> {
48 | return listOf()
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/spec-partitioner/src/main/kotlin/org/archguard/spec/partition/Partitioner.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.partition
2 |
3 | import org.archguard.spec.base.Rule
4 |
5 | interface Partitioner {
6 | fun partition(): List>
7 | }
8 |
--------------------------------------------------------------------------------
/spec-partitioner/src/main/resources/restful/status-code.txt:
--------------------------------------------------------------------------------
1 | 你是一个架构治理专家,请分析下面的 RESTful API 文档,整理文档中的状态码。要求如下:
2 |
3 | 1. 你需要按格式返回,不做解释。
4 | 2. 你的返回格式如下:
5 |
6 | ```kotlin
7 | status_code(200, 201, 202)
8 | ```
9 |
10 | 文档如下:
11 |
12 | ###
13 | {{documents}}
14 | ###
15 |
16 |
--------------------------------------------------------------------------------
/spec-partitioner/src/main/resources/restful/uri-construction.txt:
--------------------------------------------------------------------------------
1 | 你是一个架构治理专家,请分析下面的 RESTful API 文档,编写对应的正则表达式与 URI 示例。要求如下:
2 |
3 | 1. 请将 API 文档中的 URI 规则与正则表达式一一对应。
4 | 2. 尽可能只用一个正则表达式来匹配所有的 URI 规则。
5 | 3. 你编写的 URI 示例应该符合正则表达式的规则。
6 | 4. 如果文档中缺少通用的 URI 规则,请自行补充。
7 | 5. 你最后只返回如下的格式:
8 |
9 | ###
10 | ```kotlin
11 | uri_construction {
12 | rule("{{regex expression}}")
13 | example("{{uri example}}")
14 | }
15 | ```
16 | ###
17 |
18 | RESTful API 文档:
19 |
20 | ###
21 | {{documents}}
22 | ###
23 |
--------------------------------------------------------------------------------
/spec-partitioner/src/test/kotlin/org/archguard/spec/ApiPartitionerTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec
2 |
3 | import org.archguard.spec.partition.ApiPartitioner
4 | import org.junit.jupiter.api.Test
5 |
6 | class ApiPartitionerTest {
7 | @Test
8 | fun sample_for_split() {
9 | val partitioner = ApiPartitioner()
10 |
11 | partitioner.partition()
12 | }
13 | }
--------------------------------------------------------------------------------
/spec-runtime/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(projects.specLang)
9 | implementation(projects.llmCore)
10 |
11 | implementation(libs.serialization.json)
12 | implementation(libs.kotlin.stdlib)
13 | implementation(libs.kotlin.reflect)
14 |
15 | implementation(libs.slf4j.simple)
16 |
17 | implementation(libs.kotlin.scripting.jvm)
18 | implementation(libs.jupyter.api)
19 | implementation(libs.jupyter.kernel)
20 | implementation(libs.jupyter.shared.compiler)
21 |
22 | testImplementation(libs.bundles.test)
23 | testRuntimeOnly(libs.test.junit.engine)
24 | }
25 |
--------------------------------------------------------------------------------
/spec-runtime/src/main/kotlin/org/archguard/spec/runtime/api/InterpreterRequest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.runtime.interpreter.api
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class InterpreterRequest(
7 | var id: Int = -1,
8 | var code: String,
9 | val language: String = "kotlin",
10 | val history: Boolean = false,
11 | var port: Int = 8080
12 | )
13 |
--------------------------------------------------------------------------------
/spec-runtime/src/main/kotlin/org/archguard/spec/runtime/compiler/ExtendLibraries.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.runtime.compiler
2 |
3 | import org.jetbrains.kotlinx.jupyter.libraries.LibraryResolver
4 |
5 | fun extendLibraries(): LibraryResolver {
6 | return listOf>().toLibraries()
7 | }
8 |
--------------------------------------------------------------------------------
/spec-runtime/src/main/kotlin/org/archguard/spec/runtime/messaging/Message.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.runtime.messaging
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class Message(
7 | var id: Int = -1,
8 | var resultValue: String,
9 | var displayValue: String,
10 | var className: String = "",
11 | var msgType: MessageType = MessageType.NONE,
12 | var content: MessageContent? = null,
13 | )
14 |
15 |
--------------------------------------------------------------------------------
/spec-runtime/src/test/kotlin/org/archguard/spec/runtime/KotlinInterpreterTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.runtime
2 |
3 | import io.kotest.matchers.shouldBe
4 | import org.archguard.spec.runtime.interpreter.api.InterpreterRequest
5 | import org.archguard.spec.runtime.messaging.MessageType
6 | import org.junit.jupiter.api.Test
7 |
8 | class KotlinInterpreterTest {
9 | @Test
10 | fun should_return_correct_message_from_kotlin_interpreter() {
11 | val interpreter = KotlinInterpreter()
12 | val message = interpreter.eval(InterpreterRequest(code = "1 + 2"))
13 |
14 | message.resultValue shouldBe "3"
15 | message.className shouldBe "java.lang.Integer"
16 | message.msgType shouldBe MessageType.NONE
17 | message.content shouldBe null
18 | }
19 |
20 | @Test
21 | fun should_cast_to_int() {
22 | val interpreter = KotlinInterpreter()
23 | val result = interpreter.evalCast(InterpreterRequest(code = "1 + 2"))
24 | result shouldBe 3
25 | }
26 | }
--------------------------------------------------------------------------------
/spec-runtime/src/test/kotlin/org/archguard/spec/runtime/compiler/KotlinReplWrapperTest.kt:
--------------------------------------------------------------------------------
1 | package org.archguard.spec.runtime.compiler
2 |
3 | import io.kotest.matchers.shouldBe
4 | import org.junit.jupiter.api.Test
5 |
6 | import org.junit.jupiter.api.Assertions.*
7 | import org.junit.jupiter.api.BeforeEach
8 |
9 | class KotlinReplWrapperTest {
10 |
11 | private lateinit var compiler: KotlinReplWrapper
12 |
13 | @BeforeEach
14 | internal fun setUp() {
15 | this.compiler = KotlinReplWrapper()
16 | }
17 |
18 | @Test
19 | internal fun simple_eval() {
20 | compiler.eval("val x = 3")
21 | val res = compiler.eval("x*2")
22 | res.rawValue shouldBe 6
23 | }
24 | }
--------------------------------------------------------------------------------