oldg591 commited on
Commit
3459571
·
0 Parent(s):
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .devcontainer/devcontainer.json +4 -0
  2. .dockerignore +1 -0
  3. .github/ISSUE_TEMPLATE/bug_report.yml +82 -0
  4. .github/ISSUE_TEMPLATE/config.yml +7 -0
  5. .github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  6. .github/ISSUE_TEMPLATE/epic-request.md +25 -0
  7. .github/ISSUE_TEMPLATE/feature_request.yml +44 -0
  8. .github/pull_request_template.md +14 -0
  9. .github/release-drafter.yml +24 -0
  10. .github/scripts/auto-sign.sh +12 -0
  11. .github/workflows/auto-assign-author.yml +14 -0
  12. .github/workflows/auto-assign-milestone.yml +46 -0
  13. .github/workflows/auto-label-conventional-commits.yaml +35 -0
  14. .github/workflows/jan-electron-build-nightly.yml +156 -0
  15. .github/workflows/jan-electron-build.yml +138 -0
  16. .github/workflows/jan-electron-linter-and-test.yml +321 -0
  17. .github/workflows/jan-server-build-nightly.yml +40 -0
  18. .github/workflows/jan-server-build.yml +30 -0
  19. .github/workflows/nightly-integrate-cortex-cpp.yml +127 -0
  20. .github/workflows/template-build-jan-server.yml +39 -0
  21. .github/workflows/template-build-linux-x64.yml +116 -0
  22. .github/workflows/template-build-macos-arm64.yml +161 -0
  23. .github/workflows/template-build-macos-x64.yml +161 -0
  24. .github/workflows/template-build-windows-x64.yml +144 -0
  25. .github/workflows/template-get-update-version.yml +58 -0
  26. .github/workflows/template-noti-discord-and-update-url-readme.yml +57 -0
  27. .gitignore +41 -0
  28. .husky/pre-commit +4 -0
  29. .prettierignore +5 -0
  30. .prettierrc +7 -0
  31. Dockerfile +60 -0
  32. Dockerfile.gpu +87 -0
  33. LICENSE +660 -0
  34. Makefile +155 -0
  35. README.md +352 -0
  36. charts/server/Chart.lock +6 -0
  37. charts/server/Chart.yaml +10 -0
  38. charts/server/charts/common-0.1.2.tgz +0 -0
  39. charts/server/config.json +4 -0
  40. charts/server/values.yaml +256 -0
  41. core/.editorconfig +13 -0
  42. core/.gitignore +9 -0
  43. core/README.md +69 -0
  44. core/jest.config.js +7 -0
  45. core/package.json +64 -0
  46. core/rollup.config.ts +85 -0
  47. core/src/@global/index.d.ts +10 -0
  48. core/src/browser/core.ts +165 -0
  49. core/src/browser/events.ts +35 -0
  50. core/src/browser/extension.ts +211 -0
.devcontainer/devcontainer.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "name": "jan",
3
+ "image": "node:20"
4
+ }
.dockerignore ADDED
@@ -0,0 +1 @@
 
 
1
+ **/node_modules
.github/ISSUE_TEMPLATE/bug_report.yml ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: "\U0001F41B Bug Report"
2
+ description: "If something isn't working as expected \U0001F914"
3
+ labels: [ "type: bug" ]
4
+ title: 'bug: [DESCRIPTION]'
5
+
6
+ body:
7
+ - type: markdown
8
+ attributes:
9
+ value: "Thanks for taking the time to fill out this bug report!"
10
+
11
+ - type: checkboxes
12
+ attributes:
13
+ label: "#"
14
+ description: "Please search [here](./?q=is%3Aissue) to see if an issue already exists for the bug you encountered"
15
+ options:
16
+ - label: "I have searched the existing issues"
17
+ required: false
18
+
19
+ - type: textarea
20
+ validations:
21
+ required: true
22
+ attributes:
23
+ label: "Current behavior"
24
+ description: "A clear and concise description of what the bug is"
25
+
26
+ - type: textarea
27
+ validations:
28
+ required: true
29
+ attributes:
30
+ label: "Minimum reproduction step"
31
+ description: |
32
+ Please list out steps to reproduce the behavior
33
+ placeholder: |
34
+ 1. Go to '...'
35
+ 2. Click on '....'
36
+ 3. Scroll down to '....'
37
+ 4. See error
38
+
39
+ - type: textarea
40
+ validations:
41
+ required: true
42
+ attributes:
43
+ label: "Expected behavior"
44
+ description: "A clear and concise description of what you expected to happen"
45
+
46
+ - type: textarea
47
+ validations:
48
+ required: true
49
+ attributes:
50
+ label: "Screenshots / Logs"
51
+ description: |
52
+ Kindly provide your screenshots / [usage logs](https://jan.ai/docs/troubleshooting#how-to-get-error-logs) that could be helpful in diagnosing the problem
53
+ **Tip:** You can attach images, recordings or log files by clicking this area to highlight it and then dragging files in
54
+ - type: markdown
55
+ attributes:
56
+ value: |
57
+ ---
58
+
59
+ - type: input
60
+ validations:
61
+ required: true
62
+ attributes:
63
+ label: "Jan version"
64
+ description: "**Tip:** The version is located in the lower right conner of the Jan app"
65
+ placeholder: "e.g. 0.5.x-xxx nightly or stable"
66
+
67
+ - type: checkboxes
68
+ attributes:
69
+ label: "In which operating systems have you tested?"
70
+ options:
71
+ - label: macOS
72
+ - label: Windows
73
+ - label: Linux
74
+
75
+ - type: textarea
76
+ attributes:
77
+ label: "Environment details"
78
+ description: |
79
+ - Operating System: [Specify your OS details: e.g., MacOS Sonoma 14.2.1, Windows 11, Ubuntu 22, etc]
80
+ - Processor: [e.g., Apple M1, Intel Core i7, AMD Ryzen 5, etc]
81
+ - RAM: [e.g., 8GB, 16GB]
82
+ - Any additional relevant hardware specifics: [e.g., Graphics card, SSD/HDD]
.github/ISSUE_TEMPLATE/config.yml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ ## To encourage contributors to use issue templates, we don't allow blank issues
2
+ blank_issues_enabled: true
3
+
4
+ contact_links:
5
+ - name: "\u2753 Our GitHub Discussions page"
6
+ url: "https://github.com/orgs/janhq/discussions/categories/q-a"
7
+ about: "Please ask and answer questions here!"
.github/ISSUE_TEMPLATE/documentation-request.md ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: "📖 Documentation request"
3
+ about: Documentation requests
4
+ title: 'docs: TITLE'
5
+ labels: 'type: documentation'
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Pages**
11
+ - Page(s) that need to be done
12
+
13
+ **Success Criteria**
14
+ Content that should be covered
15
+
16
+ **Additional context**
17
+ Examples, reference pages, resources
.github/ISSUE_TEMPLATE/epic-request.md ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: "💥 Epic request"
3
+ about: Suggest an idea for this project
4
+ title: 'epic: [DESCRIPTION]'
5
+ labels: 'type: epic'
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ## Motivation
11
+ -
12
+
13
+ ## Specs
14
+ -
15
+
16
+ ## Designs
17
+ [Figma](link)
18
+
19
+ ## Tasklist
20
+ - [ ]
21
+
22
+ ## Not in Scope
23
+ -
24
+
25
+ ## Appendix
.github/ISSUE_TEMPLATE/feature_request.yml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: "\U0001F680 Feature Request"
2
+ description: "Suggest an idea for this project \U0001F63B!"
3
+ title: 'feat: [DESCRIPTION]'
4
+ labels: 'type: feature request'
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: "Thanks for taking the time to fill out this form!"
9
+
10
+ - type: checkboxes
11
+ attributes:
12
+ label: "#"
13
+ description: "Please search [here](./?q=is%3Aissue) to see if an issue already exists for the feature you are requesting"
14
+ options:
15
+ - label: "I have searched the existing issues"
16
+ required: false
17
+
18
+ - type: textarea
19
+ validations:
20
+ required: true
21
+ attributes:
22
+ label: "Is your feature request related to a problem? Please describe it"
23
+ description: "A clear and concise description of what the problem is"
24
+ placeholder: |
25
+ I'm always frustrated when ...
26
+
27
+ - type: textarea
28
+ validations:
29
+ required: true
30
+ attributes:
31
+ label: "Describe the solution"
32
+ description: "Description of what you want to happen. Add any considered drawbacks"
33
+
34
+ - type: textarea
35
+ attributes:
36
+ label: "Teachability, documentation, adoption, migration strategy"
37
+ description: "Explain how users will be able to use this and possibly write out something for the docs. Maybe a screenshot or design?"
38
+
39
+ - type: textarea
40
+ validations:
41
+ required: true
42
+ attributes:
43
+ label: "What is the motivation / use case for changing the behavior?"
44
+ description: "Describe the motivation or the concrete use case"
.github/pull_request_template.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Describe Your Changes
2
+
3
+ -
4
+
5
+ ## Fixes Issues
6
+
7
+ - Closes #
8
+ - Closes #
9
+
10
+ ## Self Checklist
11
+
12
+ - [ ] Added relevant comments, esp in complex areas
13
+ - [ ] Updated docs (for bug fixes / features)
14
+ - [ ] Created issues for follow-up changes or refactoring needed
.github/release-drafter.yml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ categories:
2
+ - title: "🚀 Features"
3
+ labels:
4
+ - "type: feature request"
5
+ - "type: enhancement"
6
+ - "type: epic"
7
+ - title: "🐛 Fixes"
8
+ labels:
9
+ - "type: bug"
10
+ - title: "🧰 Maintenance"
11
+ labels:
12
+ - "type: chore"
13
+ - "type: ci"
14
+ - "type: documentation"
15
+ change-template: "- $TITLE @$AUTHOR (#$NUMBER)"
16
+ change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
17
+ template: |
18
+ ## Changes
19
+
20
+ $CHANGES
21
+
22
+ ## Contributor
23
+
24
+ $CONTRIBUTORS
.github/scripts/auto-sign.sh ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Check if both APP_PATH and DEVELOPER_ID environment variables are set
4
+ if [[ -z "$APP_PATH" ]] || [[ -z "$DEVELOPER_ID" ]]; then
5
+ echo "Either APP_PATH or DEVELOPER_ID is not set. Skipping script execution."
6
+ exit 0
7
+ fi
8
+
9
+ # If both variables are set, execute the following commands
10
+ find "$APP_PATH" \( -type f -perm +111 -o -name "*.node" \) -exec codesign --force -s "$DEVELOPER_ID" --options=runtime {} \;
11
+
12
+ find "$APP_PATH" -type f -name "*.o" -exec codesign --force -s "$DEVELOPER_ID" --options=runtime {} \;
.github/workflows/auto-assign-author.yml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Auto assign author, tags, and reviewers to pull requests
2
+ name: "Auto Assign Author"
3
+ on:
4
+ pull_request:
5
+ types: [opened]
6
+ jobs:
7
+ assign-author:
8
+ runs-on: ubuntu-latest
9
+ permissions:
10
+ pull-requests: write
11
+ steps:
12
+ - uses: toshimaru/auto-author-assign@v1.1.0
13
+ with:
14
+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
.github/workflows/auto-assign-milestone.yml ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Pipeline auto assign current milestone for PR after the PR is merge
2
+ name: Assign Milestone
3
+ on:
4
+ pull_request:
5
+ types: [closed]
6
+
7
+ jobs:
8
+ assign_milestone:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ pull-requests: write
12
+ issues: write
13
+ steps:
14
+ - name: Assign Milestone
15
+ uses: actions/github-script@v3
16
+ with:
17
+ github-token: ${{ secrets.GITHUB_TOKEN }}
18
+ script: |
19
+ const { owner, repo } = context.repo;
20
+ const { number, merged } = context.payload.pull_request;
21
+ if (merged) {
22
+ const { data: milestones } = await github.issues.listMilestones({
23
+ owner,
24
+ repo,
25
+ state: 'open',
26
+ });
27
+
28
+ const mergedDate = new Date(context.payload.pull_request.merged_at);
29
+ const currentMilestone = milestones
30
+ .filter(milestone => milestone.due_on !== null)
31
+ .find((milestone) => {
32
+ const dueDate = new Date(milestone.due_on);
33
+ return mergedDate <= dueDate;
34
+ });
35
+
36
+ if (currentMilestone) {
37
+ await github.issues.update({
38
+ owner,
39
+ repo,
40
+ issue_number: number,
41
+ milestone: currentMilestone.number
42
+ });
43
+ }
44
+ }
45
+ debug: true
46
+
.github/workflows/auto-label-conventional-commits.yaml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: "Auto Label Conventional Commits"
2
+ on:
3
+ pull_request:
4
+ types:
5
+ - reopened
6
+ - opened
7
+ jobs:
8
+ label_prs:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ pull-requests: write
12
+ steps:
13
+ - name: Checkout
14
+ uses: actions/checkout@v4
15
+ - name: Label PRs
16
+ run: |
17
+ ISSUE_TITLE=$(gh issue view ${{ github.event.number }} --json title -q ".title")
18
+ case "$ISSUE_TITLE" in
19
+ chore:*) LABEL="type: chore" ;;
20
+ feat:*) LABEL="type: feature request" ;;
21
+ perf:*) LABEL="type: enhancement" ;;
22
+ fix:*) LABEL="type: bug" ;;
23
+ docs:*) LABEL="type: documentation" ;;
24
+ ci:*) LABEL="type: ci" ;;
25
+ build:*) LABEL="type: ci" ;;
26
+ test:*) LABEL="type: chore" ;;
27
+ style:*) LABEL="type: chore" ;;
28
+ refactor:*) LABEL="type: chore" ;;
29
+ *) LABEL="" ;;
30
+ esac
31
+ if [ -n "$LABEL" ]; then
32
+ gh issue edit ${{ github.event.number }} --add-label "$LABEL"
33
+ fi
34
+ env:
35
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
.github/workflows/jan-electron-build-nightly.yml ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Electron Builder - Nightly / Manual
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '0 20 * * 1,2,3' # At 8 PM UTC on Monday, Tuesday, and Wednesday which is 3 AM UTC+7 Tuesday, Wednesday, and Thursday
6
+ workflow_dispatch:
7
+ inputs:
8
+ public_provider:
9
+ type: choice
10
+ description: 'Public Provider'
11
+ options:
12
+ - none
13
+ - cloudflare-r2
14
+ default: none
15
+
16
+ jobs:
17
+ set-public-provider:
18
+ runs-on: ubuntu-latest
19
+ outputs:
20
+ public_provider: ${{ steps.set-public-provider.outputs.public_provider }}
21
+ ref: ${{ steps.set-public-provider.outputs.ref }}
22
+ steps:
23
+ - name: Set public provider
24
+ id: set-public-provider
25
+ run: |
26
+ if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
27
+ echo "::set-output name=public_provider::${{ github.event.inputs.public_provider }}"
28
+ echo "::set-output name=ref::${{ github.ref }}"
29
+ else
30
+ if [ "${{ github.event_name }}" == "schedule" ]; then
31
+ echo "::set-output name=public_provider::cloudflare-r2"
32
+ echo "::set-output name=ref::refs/heads/dev"
33
+ elif [ "${{ github.event_name }}" == "push" ]; then
34
+ echo "::set-output name=public_provider::cloudflare-r2"
35
+ echo "::set-output name=ref::${{ github.ref }}"
36
+ else
37
+ echo "::set-output name=public_provider::none"
38
+ echo "::set-output name=ref::${{ github.ref }}"
39
+ fi
40
+ fi
41
+ # Job create Update app version based on latest release tag with build number and save to output
42
+ get-update-version:
43
+ uses: ./.github/workflows/template-get-update-version.yml
44
+
45
+ build-macos-x64:
46
+ uses: ./.github/workflows/template-build-macos-x64.yml
47
+ needs: [get-update-version, set-public-provider]
48
+ secrets: inherit
49
+ with:
50
+ ref: ${{ needs.set-public-provider.outputs.ref }}
51
+ public_provider: ${{ needs.set-public-provider.outputs.public_provider }}
52
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
53
+
54
+ build-macos-arm64:
55
+ uses: ./.github/workflows/template-build-macos-arm64.yml
56
+ needs: [get-update-version, set-public-provider]
57
+ secrets: inherit
58
+ with:
59
+ ref: ${{ needs.set-public-provider.outputs.ref }}
60
+ public_provider: ${{ needs.set-public-provider.outputs.public_provider }}
61
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
62
+
63
+ build-windows-x64:
64
+ uses: ./.github/workflows/template-build-windows-x64.yml
65
+ secrets: inherit
66
+ needs: [get-update-version, set-public-provider]
67
+ with:
68
+ ref: ${{ needs.set-public-provider.outputs.ref }}
69
+ public_provider: ${{ needs.set-public-provider.outputs.public_provider }}
70
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
71
+
72
+
73
+ build-linux-x64:
74
+ uses: ./.github/workflows/template-build-linux-x64.yml
75
+ secrets: inherit
76
+ needs: [get-update-version, set-public-provider]
77
+ with:
78
+ ref: ${{ needs.set-public-provider.outputs.ref }}
79
+ public_provider: ${{ needs.set-public-provider.outputs.public_provider }}
80
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
81
+
82
+ combine-latest-mac-yml:
83
+ needs: [set-public-provider, build-macos-x64, build-macos-arm64]
84
+ runs-on: ubuntu-latest
85
+ steps:
86
+ - name: Getting the repo
87
+ uses: actions/checkout@v3
88
+ with:
89
+ ref: ${{ needs.set-public-provider.outputs.ref }}
90
+ - name: Download mac-x64 artifacts
91
+ uses: actions/download-artifact@v3
92
+ with:
93
+ name: latest-mac-x64
94
+ path: ./latest-mac-x64
95
+ - name: Download mac-arm artifacts
96
+ uses: actions/download-artifact@v3
97
+ with:
98
+ name: latest-mac-arm64
99
+ path: ./latest-mac-arm64
100
+
101
+ - name: 'Merge latest-mac.yml'
102
+ # unfortunately electron-builder doesn't understand that we have two different releases for mac-x64 and mac-arm, so we need to manually merge the latest files
103
+ # see https://github.com/electron-userland/electron-builder/issues/5592
104
+ run: |
105
+ ls -la .
106
+ ls -la ./latest-mac-x64
107
+ ls -la ./latest-mac-arm64
108
+ ls -la ./electron
109
+ cp ./electron/merge-latest-ymls.js /tmp/merge-latest-ymls.js
110
+ npm install js-yaml --prefix /tmp
111
+ node /tmp/merge-latest-ymls.js ./latest-mac-x64/latest-mac.yml ./latest-mac-arm64/latest-mac.yml ./latest-mac.yml
112
+ cat ./latest-mac.yml
113
+
114
+ - name: Upload latest-mac.yml
115
+ if: ${{ needs.set-public-provider.outputs.public_provider == 'cloudflare-r2' }}
116
+ run: |
117
+ aws s3api put-object --endpoint-url https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com --bucket ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }} --key "latest/latest-mac.yml" --body "./latest-mac.yml"
118
+ env:
119
+ AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }}
120
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }}
121
+ AWS_DEFAULT_REGION: auto
122
+ AWS_EC2_METADATA_DISABLED: "true"
123
+
124
+
125
+ noti-discord-nightly-and-update-url-readme:
126
+ needs: [build-macos-x64, build-macos-arm64, build-windows-x64, build-linux-x64, get-update-version, set-public-provider, combine-latest-mac-yml]
127
+ secrets: inherit
128
+ if: github.event_name == 'schedule'
129
+ uses: ./.github/workflows/template-noti-discord-and-update-url-readme.yml
130
+ with:
131
+ ref: refs/heads/dev
132
+ build_reason: Nightly
133
+ push_to_branch: dev
134
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
135
+
136
+ noti-discord-pre-release-and-update-url-readme:
137
+ needs: [build-macos-x64, build-macos-arm64, build-windows-x64, build-linux-x64, get-update-version, set-public-provider, combine-latest-mac-yml]
138
+ secrets: inherit
139
+ if: github.event_name == 'push'
140
+ uses: ./.github/workflows/template-noti-discord-and-update-url-readme.yml
141
+ with:
142
+ ref: refs/heads/dev
143
+ build_reason: Pre-release
144
+ push_to_branch: dev
145
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
146
+
147
+ noti-discord-manual-and-update-url-readme:
148
+ needs: [build-macos-x64, build-macos-arm64, build-windows-x64, build-linux-x64, get-update-version, set-public-provider, combine-latest-mac-yml]
149
+ secrets: inherit
150
+ if: github.event_name == 'workflow_dispatch' && github.event.inputs.public_provider == 'cloudflare-r2'
151
+ uses: ./.github/workflows/template-noti-discord-and-update-url-readme.yml
152
+ with:
153
+ ref: refs/heads/dev
154
+ build_reason: Manual
155
+ push_to_branch: dev
156
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
.github/workflows/jan-electron-build.yml ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Electron Builder - Tag
2
+
3
+ on:
4
+ push:
5
+ tags: ["v[0-9]+.[0-9]+.[0-9]+"]
6
+
7
+ jobs:
8
+ # Job create Update app version based on latest release tag with build number and save to output
9
+ get-update-version:
10
+ uses: ./.github/workflows/template-get-update-version.yml
11
+
12
+ create-draft-release:
13
+ runs-on: ubuntu-latest
14
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
15
+ outputs:
16
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
17
+ version: ${{ steps.get_version.outputs.version }}
18
+ permissions:
19
+ contents: write
20
+ steps:
21
+ - name: Extract tag name without v prefix
22
+ id: get_version
23
+ run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV && echo "::set-output name=version::${GITHUB_REF#refs/tags/v}"
24
+ env:
25
+ GITHUB_REF: ${{ github.ref }}
26
+ - name: Create Draft Release
27
+ id: create_release
28
+ uses: softprops/action-gh-release@v2
29
+ with:
30
+ tag_name: ${{ github.ref_name }}
31
+ token: ${{ secrets.GITHUB_TOKEN }}
32
+ name: "${{ env.VERSION }}"
33
+ draft: true
34
+ prerelease: false
35
+
36
+ build-macos-x64:
37
+ uses: ./.github/workflows/template-build-macos-x64.yml
38
+ secrets: inherit
39
+ needs: [get-update-version]
40
+ with:
41
+ ref: ${{ github.ref }}
42
+ public_provider: github
43
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
44
+
45
+ build-macos-arm64:
46
+ uses: ./.github/workflows/template-build-macos-arm64.yml
47
+ secrets: inherit
48
+ needs: [get-update-version]
49
+ with:
50
+ ref: ${{ github.ref }}
51
+ public_provider: github
52
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
53
+
54
+ build-windows-x64:
55
+ uses: ./.github/workflows/template-build-windows-x64.yml
56
+ secrets: inherit
57
+ needs: [get-update-version]
58
+ with:
59
+ ref: ${{ github.ref }}
60
+ public_provider: github
61
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
62
+
63
+ build-linux-x64:
64
+ uses: ./.github/workflows/template-build-linux-x64.yml
65
+ secrets: inherit
66
+ needs: [get-update-version]
67
+ with:
68
+ ref: ${{ github.ref }}
69
+ public_provider: github
70
+ new_version: ${{ needs.get-update-version.outputs.new_version }}
71
+
72
+ combine-latest-mac-yml:
73
+ needs: [build-macos-x64, build-macos-arm64, create-draft-release]
74
+ runs-on: ubuntu-latest
75
+ permissions:
76
+ contents: write
77
+ steps:
78
+ - name: Getting the repo
79
+ uses: actions/checkout@v3
80
+
81
+ - name: Download mac-x64 artifacts
82
+ uses: actions/download-artifact@v3
83
+ with:
84
+ name: latest-mac-x64
85
+ path: ./latest-mac-x64
86
+ - name: Download mac-arm artifacts
87
+ uses: actions/download-artifact@v3
88
+ with:
89
+ name: latest-mac-arm64
90
+ path: ./latest-mac-arm64
91
+
92
+ - name: 'Merge latest-mac.yml'
93
+ # unfortunately electron-builder doesn't understand that we have two different releases for mac-x64 and mac-arm, so we need to manually merge the latest files
94
+ # see https://github.com/electron-userland/electron-builder/issues/5592
95
+ run: |
96
+ ls -la .
97
+ ls -la ./latest-mac-x64
98
+ ls -la ./latest-mac-arm64
99
+ ls -la ./electron
100
+ cp ./electron/merge-latest-ymls.js /tmp/merge-latest-ymls.js
101
+ npm install js-yaml --prefix /tmp
102
+ node /tmp/merge-latest-ymls.js ./latest-mac-x64/latest-mac.yml ./latest-mac-arm64/latest-mac.yml ./latest-mac.yml
103
+ cat ./latest-mac.yml
104
+
105
+ - name: Yet Another Upload Release Asset Action
106
+ uses: shogo82148/actions-upload-release-asset@v1.7.2
107
+ env:
108
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
109
+ with:
110
+ upload_url: ${{ needs.create-draft-release.outputs.upload_url }}
111
+ asset_path: ./latest-mac.yml
112
+ asset_name: latest-mac.yml
113
+ asset_content_type: text/yaml
114
+ overwrite: true
115
+
116
+ update_release_draft:
117
+ needs: [build-macos-x64, build-macos-arm64, build-windows-x64, build-linux-x64, combine-latest-mac-yml]
118
+ permissions:
119
+ # write permission is required to create a github release
120
+ contents: write
121
+ # write permission is required for autolabeler
122
+ # otherwise, read permission is required at least
123
+ pull-requests: write
124
+ runs-on: ubuntu-latest
125
+ steps:
126
+ # (Optional) GitHub Enterprise requires GHE_HOST variable set
127
+ #- name: Set GHE_HOST
128
+ # run: |
129
+ # echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV
130
+
131
+ # Drafts your next Release notes as Pull Requests are merged into "master"
132
+ - uses: release-drafter/release-drafter@v5
133
+ # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
134
+ # with:
135
+ # config-name: my-config.yml
136
+ # disable-autolabeler: true
137
+ env:
138
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
.github/workflows/jan-electron-linter-and-test.yml ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Test - Linter & Playwright
2
+ on:
3
+ workflow_dispatch:
4
+ push:
5
+ branches:
6
+ - main
7
+ - dev
8
+ paths:
9
+ - 'electron/**'
10
+ - .github/workflows/jan-electron-linter-and-test.yml
11
+ - 'web/**'
12
+ - 'joi/**'
13
+ - 'package.json'
14
+ - 'node_modules/**'
15
+ - 'yarn.lock'
16
+ - 'core/**'
17
+ - 'extensions/**'
18
+ - '!README.md'
19
+ - 'Makefile'
20
+
21
+ pull_request:
22
+ branches:
23
+ - main
24
+ - dev
25
+ - release/**
26
+ paths:
27
+ - 'electron/**'
28
+ - .github/workflows/jan-electron-linter-and-test.yml
29
+ - 'web/**'
30
+ - 'joi/**'
31
+ - 'package.json'
32
+ - 'node_modules/**'
33
+ - 'yarn.lock'
34
+ - 'Makefile'
35
+ - 'extensions/**'
36
+ - 'core/**'
37
+ - '!README.md'
38
+
39
+ jobs:
40
+ test-on-macos:
41
+ if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
42
+ runs-on: [self-hosted, macOS, macos-desktop]
43
+ steps:
44
+ - name: Getting the repo
45
+ uses: actions/checkout@v3
46
+ with:
47
+ fetch-depth: 0
48
+
49
+ - name: Installing node
50
+ uses: actions/setup-node@v3
51
+ with:
52
+ node-version: 20
53
+
54
+ - name: 'Cleanup cache'
55
+ continue-on-error: true
56
+ run: |
57
+ rm -rf ~/jan
58
+ make clean
59
+
60
+ - name: Get Commit Message for PR
61
+ if: github.event_name == 'pull_request'
62
+ run: |
63
+ echo "REPORT_PORTAL_DESCRIPTION=${{github.event.after}})" >> $GITHUB_ENV
64
+
65
+ - name: Get Commit Message for push event
66
+ if: github.event_name == 'push'
67
+ run: |
68
+ echo "REPORT_PORTAL_DESCRIPTION=${{github.sha}})" >> $GITHUB_ENV
69
+
70
+ - name: 'Config report portal'
71
+ run: |
72
+ make update-playwright-config REPORT_PORTAL_URL=${{ secrets.REPORT_PORTAL_URL }} REPORT_PORTAL_API_KEY=${{ secrets.REPORT_PORTAL_API_KEY }} REPORT_PORTAL_PROJECT_NAME=${{ secrets.REPORT_PORTAL_PROJECT_NAME }} REPORT_PORTAL_LAUNCH_NAME="Jan App macos" REPORT_PORTAL_DESCRIPTION="${{env.REPORT_PORTAL_DESCRIPTION}}"
73
+
74
+ - name: Linter and test
75
+ run: |
76
+ npm config set registry ${{ secrets.NPM_PROXY }} --global
77
+ yarn config set registry ${{ secrets.NPM_PROXY }} --global
78
+ make test
79
+ env:
80
+ CSC_IDENTITY_AUTO_DISCOVERY: 'false'
81
+ TURBO_API: '${{ secrets.TURBO_API }}'
82
+ TURBO_TEAM: 'macos'
83
+ TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'
84
+
85
+ test-on-macos-pr-target:
86
+ if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
87
+ runs-on: [self-hosted, macOS, macos-desktop]
88
+ steps:
89
+ - name: Getting the repo
90
+ uses: actions/checkout@v3
91
+ with:
92
+ fetch-depth: 0
93
+
94
+ - name: Installing node
95
+ uses: actions/setup-node@v3
96
+ with:
97
+ node-version: 20
98
+
99
+ - name: 'Cleanup cache'
100
+ continue-on-error: true
101
+ run: |
102
+ rm -rf ~/jan
103
+ make clean
104
+
105
+ - name: Linter and test
106
+ run: |
107
+ npm config set registry https://registry.npmjs.org --global
108
+ yarn config set registry https://registry.npmjs.org --global
109
+ make test
110
+ env:
111
+ CSC_IDENTITY_AUTO_DISCOVERY: 'false'
112
+
113
+ test-on-windows:
114
+ if: github.event_name == 'push'
115
+ strategy:
116
+ fail-fast: false
117
+ matrix:
118
+ antivirus-tools: ['mcafee', 'default-windows-security', 'bit-defender']
119
+ runs-on: windows-desktop-${{ matrix.antivirus-tools }}
120
+ steps:
121
+ - name: Getting the repo
122
+ uses: actions/checkout@v3
123
+ with:
124
+ fetch-depth: 0
125
+
126
+ - name: Installing node
127
+ uses: actions/setup-node@v3
128
+ with:
129
+ node-version: 20
130
+
131
+ # Clean cache, continue on error
132
+ - name: 'Cleanup cache'
133
+ shell: powershell
134
+ continue-on-error: true
135
+ run: |
136
+ $path = "$Env:APPDATA\jan"
137
+ if (Test-Path $path) {
138
+ Remove-Item "\\?\$path" -Recurse -Force
139
+ } else {
140
+ Write-Output "Folder does not exist."
141
+ }
142
+ make clean
143
+
144
+ - name: Get Commit Message for push event
145
+ if: github.event_name == 'push'
146
+ shell: bash
147
+ run: |
148
+ echo "REPORT_PORTAL_DESCRIPTION=${{github.sha}}" >> $GITHUB_ENV
149
+
150
+ - name: 'Config report portal'
151
+ shell: bash
152
+ run: |
153
+ make update-playwright-config REPORT_PORTAL_URL=${{ secrets.REPORT_PORTAL_URL }} REPORT_PORTAL_API_KEY=${{ secrets.REPORT_PORTAL_API_KEY }} REPORT_PORTAL_PROJECT_NAME=${{ secrets.REPORT_PORTAL_PROJECT_NAME }} REPORT_PORTAL_LAUNCH_NAME="Jan App Windows ${{ matrix.antivirus-tools }}" REPORT_PORTAL_DESCRIPTION="${{env.REPORT_PORTAL_DESCRIPTION}}"
154
+
155
+ - name: Linter and test
156
+ shell: powershell
157
+ run: |
158
+ npm config set registry ${{ secrets.NPM_PROXY }} --global
159
+ yarn config set registry ${{ secrets.NPM_PROXY }} --global
160
+ make test
161
+ env:
162
+ TURBO_API: '${{ secrets.TURBO_API }}'
163
+ TURBO_TEAM: 'windows'
164
+ TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'
165
+ test-on-windows-pr:
166
+ if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
167
+ runs-on: windows-desktop-default-windows-security
168
+ steps:
169
+ - name: Getting the repo
170
+ uses: actions/checkout@v3
171
+ with:
172
+ fetch-depth: 0
173
+
174
+ - name: Installing node
175
+ uses: actions/setup-node@v1
176
+ with:
177
+ node-version: 20
178
+
179
+ # Clean cache, continue on error
180
+ - name: 'Cleanup cache'
181
+ shell: powershell
182
+ continue-on-error: true
183
+ run: |
184
+ $path = "$Env:APPDATA\jan"
185
+ if (Test-Path $path) {
186
+ Remove-Item "\\?\$path" -Recurse -Force
187
+ } else {
188
+ Write-Output "Folder does not exist."
189
+ }
190
+ make clean
191
+
192
+ - name: Get Commit Message for PR
193
+ if: github.event_name == 'pull_request'
194
+ shell: bash
195
+ run: |
196
+ echo "REPORT_PORTAL_DESCRIPTION=${{github.event.after}}" >> $GITHUB_ENV
197
+
198
+ - name: 'Config report portal'
199
+ shell: bash
200
+ run: |
201
+ make update-playwright-config REPORT_PORTAL_URL=${{ secrets.REPORT_PORTAL_URL }} REPORT_PORTAL_API_KEY=${{ secrets.REPORT_PORTAL_API_KEY }} REPORT_PORTAL_PROJECT_NAME=${{ secrets.REPORT_PORTAL_PROJECT_NAME }} REPORT_PORTAL_LAUNCH_NAME="Jan App Windows" REPORT_PORTAL_DESCRIPTION="${{env.REPORT_PORTAL_DESCRIPTION}}"
202
+
203
+ - name: Linter and test
204
+ shell: powershell
205
+ run: |
206
+ npm config set registry ${{ secrets.NPM_PROXY }} --global
207
+ yarn config set registry ${{ secrets.NPM_PROXY }} --global
208
+ make test
209
+ env:
210
+ TURBO_API: '${{ secrets.TURBO_API }}'
211
+ TURBO_TEAM: 'windows'
212
+ TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'
213
+
214
+ test-on-windows-pr-target:
215
+ if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
216
+ runs-on: windows-desktop-default-windows-security
217
+ steps:
218
+ - name: Getting the repo
219
+ uses: actions/checkout@v3
220
+ with:
221
+ fetch-depth: 0
222
+
223
+ - name: Installing node
224
+ uses: actions/setup-node@v1
225
+ with:
226
+ node-version: 20
227
+
228
+ # Clean cache, continue on error
229
+ - name: 'Cleanup cache'
230
+ shell: powershell
231
+ continue-on-error: true
232
+ run: |
233
+ $path = "$Env:APPDATA\jan"
234
+ if (Test-Path $path) {
235
+ Remove-Item "\\?\$path" -Recurse -Force
236
+ } else {
237
+ Write-Output "Folder does not exist."
238
+ }
239
+ make clean
240
+
241
+ - name: Linter and test
242
+ shell: powershell
243
+ run: |
244
+ npm config set registry https://registry.npmjs.org --global
245
+ yarn config set registry https://registry.npmjs.org --global
246
+ make test
247
+
248
+ test-on-ubuntu:
249
+ runs-on: [self-hosted, Linux, ubuntu-desktop]
250
+ if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
251
+ steps:
252
+ - name: Getting the repo
253
+ uses: actions/checkout@v3
254
+ with:
255
+ fetch-depth: 0
256
+
257
+ - name: Installing node
258
+ uses: actions/setup-node@v3
259
+ with:
260
+ node-version: 20
261
+
262
+ - name: 'Cleanup cache'
263
+ continue-on-error: true
264
+ run: |
265
+ rm -rf ~/jan
266
+ make clean
267
+
268
+ - name: Get Commit Message for PR
269
+ if: github.event_name == 'pull_request'
270
+ run: |
271
+ echo "REPORT_PORTAL_DESCRIPTION=${{github.event.after}}" >> $GITHUB_ENV
272
+
273
+ - name: Get Commit Message for push event
274
+ if: github.event_name == 'push'
275
+ run: |
276
+ echo "REPORT_PORTAL_DESCRIPTION=${{github.sha}}" >> $GITHUB_ENV
277
+
278
+ - name: 'Config report portal'
279
+ shell: bash
280
+ run: |
281
+ make update-playwright-config REPORT_PORTAL_URL=${{ secrets.REPORT_PORTAL_URL }} REPORT_PORTAL_API_KEY=${{ secrets.REPORT_PORTAL_API_KEY }} REPORT_PORTAL_PROJECT_NAME=${{ secrets.REPORT_PORTAL_PROJECT_NAME }} REPORT_PORTAL_LAUNCH_NAME="Jan App Linux" REPORT_PORTAL_DESCRIPTION="${{env.REPORT_PORTAL_DESCRIPTION}}"
282
+
283
+ - name: Linter and test
284
+ run: |
285
+ export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
286
+ echo -e "Display ID: $DISPLAY"
287
+ npm config set registry ${{ secrets.NPM_PROXY }} --global
288
+ yarn config set registry ${{ secrets.NPM_PROXY }} --global
289
+ make test
290
+ env:
291
+ TURBO_API: '${{ secrets.TURBO_API }}'
292
+ TURBO_TEAM: 'linux'
293
+ TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'
294
+
295
+ test-on-ubuntu-pr-target:
296
+ runs-on: [self-hosted, Linux, ubuntu-desktop]
297
+ if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
298
+ steps:
299
+ - name: Getting the repo
300
+ uses: actions/checkout@v3
301
+ with:
302
+ fetch-depth: 0
303
+
304
+ - name: Installing node
305
+ uses: actions/setup-node@v3
306
+ with:
307
+ node-version: 20
308
+
309
+ - name: 'Cleanup cache'
310
+ continue-on-error: true
311
+ run: |
312
+ rm -rf ~/jan
313
+ make clean
314
+
315
+ - name: Linter and test
316
+ run: |
317
+ export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
318
+ echo -e "Display ID: $DISPLAY"
319
+ npm config set registry https://registry.npmjs.org --global
320
+ yarn config set registry https://registry.npmjs.org --global
321
+ make test
.github/workflows/jan-server-build-nightly.yml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Docker Builder - Nightly / Manual
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - feature/helmchart-and-ci-jan-server
8
+ paths-ignore:
9
+ - 'README.md'
10
+ - 'docs/**'
11
+ schedule:
12
+ - cron: '0 21 * * 1,2,3' # At 8 PM UTC on Monday, Tuesday, and Wednesday which is 4 AM UTC+7 Tuesday, Wednesday, and Thursday
13
+ workflow_dispatch:
14
+
15
+ jobs:
16
+ # Job create Update app version based on latest release tag with build number and save to output
17
+ get-update-version:
18
+ uses: ./.github/workflows/template-get-update-version.yml
19
+
20
+ build-cpu:
21
+ uses: ./.github/workflows/template-build-jan-server.yml
22
+ permissions:
23
+ packages: write
24
+ secrets: inherit
25
+ needs: [get-update-version]
26
+ with:
27
+ dockerfile_path: ./Dockerfile
28
+ docker_image_tag: "ghcr.io/janhq/jan-server:dev-cpu-latest,ghcr.io/janhq/jan-server:dev-cpu-${{ needs.get-update-version.outputs.new_version }}"
29
+
30
+ build-gpu:
31
+ uses: ./.github/workflows/template-build-jan-server.yml
32
+ permissions:
33
+ packages: write
34
+ secrets: inherit
35
+ needs: [get-update-version]
36
+ with:
37
+ dockerfile_path: ./Dockerfile.gpu
38
+ docker_image_tag: "ghcr.io/janhq/jan-server:dev-cuda-12.2-latest,ghcr.io/janhq/jan-server:dev-cuda-12.2-${{ needs.get-update-version.outputs.new_version }}"
39
+
40
+
.github/workflows/jan-server-build.yml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Docker Builder - Tag
2
+
3
+ on:
4
+ push:
5
+ tags: ["v[0-9]+.[0-9]+.[0-9]+"]
6
+
7
+ jobs:
8
+ # Job create Update app version based on latest release tag with build number and save to output
9
+ get-update-version:
10
+ uses: ./.github/workflows/template-get-update-version.yml
11
+
12
+ build-cpu:
13
+ permissions:
14
+ packages: write
15
+ uses: ./.github/workflows/template-build-jan-server.yml
16
+ secrets: inherit
17
+ needs: [get-update-version]
18
+ with:
19
+ dockerfile_path: ./Dockerfile
20
+ docker_image_tag: "ghcr.io/janhq/jan-server:cpu-latest,ghcr.io/janhq/jan-server:cpu-${{ needs.get-update-version.outputs.new_version }}"
21
+
22
+ build-gpu:
23
+ permissions:
24
+ packages: write
25
+ uses: ./.github/workflows/template-build-jan-server.yml
26
+ secrets: inherit
27
+ needs: [get-update-version]
28
+ with:
29
+ dockerfile_path: ./Dockerfile.gpu
30
+ docker_image_tag: "ghcr.io/janhq/jan-server:cuda-12.2-latest,ghcr.io/janhq/jan-server:cuda-12.2-${{ needs.get-update-version.outputs.new_version }}"
.github/workflows/nightly-integrate-cortex-cpp.yml ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Nightly Update cortex cpp
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '30 19 * * 1-5' # At 01:30 on every day-of-week from Monday through Friday UTC +7
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ update-submodule:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: write
13
+ pull-requests: write
14
+ actions: write
15
+
16
+ outputs:
17
+ pr_number: ${{ steps.check-update.outputs.pr_number }}
18
+ pr_created: ${{ steps.check-update.outputs.pr_created }}
19
+
20
+ steps:
21
+ - name: Checkout repository
22
+ uses: actions/checkout@v3
23
+ with:
24
+ submodules: recursive
25
+ ref: dev
26
+ fetch-depth: 0
27
+ token: ${{ secrets.PAT_SERVICE_ACCOUNT }}
28
+
29
+ - name: Configure Git
30
+ run: |
31
+ git config --global user.name 'github-actions[bot]'
32
+ git config --global user.email 'github-actions[bot]@users.noreply.github.com'
33
+
34
+ - name: Update submodule to latest release
35
+ id: check-update
36
+ env:
37
+ GITHUB_TOKEN: ${{ secrets.PAT_SERVICE_ACCOUNT }}
38
+ run: |
39
+ curl -s https://api.github.com/repos/janhq/cortex/releases > /tmp/github_api_releases.json
40
+ latest_prerelease_name=$(cat /tmp/github_api_releases.json | jq -r '.[] | select(.prerelease) | .name' | head -n 1)
41
+
42
+ get_asset_count() {
43
+ local version_name=$1
44
+ cat /tmp/github_api_releases.json | jq -r --arg version_name "$version_name" '.[] | select(.name == $version_name) | .assets | length'
45
+ }
46
+
47
+ cortex_cpp_version_file_path="extensions/inference-nitro-extension/bin/version.txt"
48
+ current_version_name=$(cat "$cortex_cpp_version_file_path" | head -n 1)
49
+
50
+ current_version_asset_count=$(get_asset_count "$current_version_name")
51
+ latest_prerelease_asset_count=$(get_asset_count "$latest_prerelease_name")
52
+
53
+ if [ "$current_version_name" = "$latest_prerelease_name" ]; then
54
+ echo "cortex cpp remote repo doesn't have update today, skip update cortex-cpp for today nightly build"
55
+ echo "::set-output name=pr_created::false"
56
+ exit 0
57
+ fi
58
+
59
+ if [ "$current_version_asset_count" != "$latest_prerelease_asset_count" ]; then
60
+ echo "Latest prerelease version has different number of assets, somethink went wrong, skip update cortex-cpp for today nightly build"
61
+ echo "::set-output name=pr_created::false"
62
+ exit 1
63
+ fi
64
+
65
+ echo $latest_prerelease_name > $cortex_cpp_version_file_path
66
+ echo "Updated version from $current_version_name to $latest_prerelease_name."
67
+ echo "::set-output name=pr_created::true"
68
+
69
+ git add -f $cortex_cpp_version_file_path
70
+ git commit -m "Update cortex cpp nightly to version $latest_prerelease_name"
71
+ branch_name="update-nightly-$(date +'%Y-%m-%d-%H-%M')"
72
+ git checkout -b $branch_name
73
+ git push origin $branch_name
74
+
75
+ pr_title="Update cortex cpp nightly to version $latest_prerelease_name"
76
+ pr_body="This PR updates the Update cortex cpp nightly to version $latest_prerelease_name"
77
+
78
+ gh pr create --title "$pr_title" --body "$pr_body" --head $branch_name --base dev --reviewer Van-QA
79
+
80
+ pr_number=$(gh pr list --head $branch_name --json number --jq '.[0].number')
81
+ echo "::set-output name=pr_number::$pr_number"
82
+
83
+ check-and-merge-pr:
84
+ needs: update-submodule
85
+ if: needs.update-submodule.outputs.pr_created == 'true'
86
+ runs-on: ubuntu-latest
87
+ permissions:
88
+ contents: write
89
+ pull-requests: write
90
+
91
+ steps:
92
+ - name: Checkout repository
93
+ uses: actions/checkout@v3
94
+ with:
95
+ submodules: recursive
96
+ fetch-depth: 0
97
+ token: ${{ secrets.PAT_SERVICE_ACCOUNT }}
98
+
99
+ - name: Wait for CI to pass
100
+ env:
101
+ GITHUB_TOKEN: ${{ secrets.PAT_SERVICE_ACCOUNT }}
102
+ run: |
103
+ pr_number=${{ needs.update-submodule.outputs.pr_number }}
104
+ while true; do
105
+ ci_completed=$(gh pr checks $pr_number --json completedAt --jq '.[].completedAt')
106
+ if echo "$ci_completed" | grep -q "0001-01-01T00:00:00Z"; then
107
+ echo "CI is still running, waiting..."
108
+ sleep 60
109
+ else
110
+ echo "CI has completed, checking states..."
111
+ ci_states=$(gh pr checks $pr_number --json state --jq '.[].state')
112
+ if echo "$ci_states" | grep -vqE "SUCCESS|SKIPPED"; then
113
+ echo "CI failed, exiting..."
114
+ exit 1
115
+ else
116
+ echo "CI passed, merging PR..."
117
+ break
118
+ fi
119
+ fi
120
+ done
121
+
122
+ - name: Merge the PR
123
+ env:
124
+ GITHUB_TOKEN: ${{ secrets.PAT_SERVICE_ACCOUNT }}
125
+ run: |
126
+ pr_number=${{ needs.update-submodule.outputs.pr_number }}
127
+ gh pr merge $pr_number --merge --admin
.github/workflows/template-build-jan-server.yml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: build-jan-server
2
+ on:
3
+ workflow_call:
4
+ inputs:
5
+ dockerfile_path:
6
+ required: false
7
+ type: string
8
+ default: './Dockerfile'
9
+ docker_image_tag:
10
+ required: true
11
+ type: string
12
+ default: 'ghcr.io/janhq/jan-server:dev-latest'
13
+
14
+ jobs:
15
+ build:
16
+ runs-on: ubuntu-latest
17
+ env:
18
+ REGISTRY: ghcr.io
19
+ IMAGE_NAME: janhq/jan-server
20
+ permissions:
21
+ packages: write
22
+ steps:
23
+ - name: Checkout
24
+ uses: actions/checkout@v4
25
+
26
+ - name: Log in to the Container registry
27
+ uses: docker/login-action@v3
28
+ with:
29
+ registry: ${{ env.REGISTRY }}
30
+ username: ${{ github.actor }}
31
+ password: ${{ secrets.GITHUB_TOKEN }}
32
+
33
+ - name: Build and push Docker image
34
+ uses: docker/build-push-action@v3
35
+ with:
36
+ context: .
37
+ file: ${{ inputs.dockerfile_path }}
38
+ push: true
39
+ tags: ${{ inputs.docker_image_tag }}
.github/workflows/template-build-linux-x64.yml ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: build-linux-x64
2
+ on:
3
+ workflow_call:
4
+ inputs:
5
+ ref:
6
+ required: true
7
+ type: string
8
+ default: 'refs/heads/main'
9
+ public_provider:
10
+ required: true
11
+ type: string
12
+ default: none
13
+ description: 'none: build only, github: build and publish to github, cloudflare: build and publish to cloudflare'
14
+ new_version:
15
+ required: true
16
+ type: string
17
+ default: ''
18
+ cloudflare_r2_path:
19
+ required: false
20
+ type: string
21
+ default: '/latest/'
22
+ secrets:
23
+ CLOUDFLARE_R2_BUCKET_NAME:
24
+ required: false
25
+ CLOUDFLARE_R2_ACCESS_KEY_ID:
26
+ required: false
27
+ CLOUDFLARE_R2_SECRET_ACCESS_KEY:
28
+ required: false
29
+ CLOUDFLARE_ACCOUNT_ID:
30
+ required: false
31
+
32
+ jobs:
33
+ build-linux-x64:
34
+ runs-on: ubuntu-latest
35
+ environment: production
36
+ permissions:
37
+ contents: write
38
+ steps:
39
+ - name: Getting the repo
40
+ uses: actions/checkout@v3
41
+ with:
42
+ ref: ${{ inputs.ref }}
43
+
44
+ - name: Installing node
45
+ uses: actions/setup-node@v1
46
+ with:
47
+ node-version: 20
48
+
49
+ - name: Install jq
50
+ uses: dcarbone/install-jq-action@v2.0.1
51
+
52
+ - name: Update app version base public_provider
53
+ if: inputs.public_provider != 'github'
54
+ run: |
55
+ echo "Version: ${{ inputs.new_version }}"
56
+ # Update the version in electron/package.json
57
+ jq --arg version "${{ inputs.new_version }}" '.version = $version' electron/package.json > /tmp/package.json
58
+ mv /tmp/package.json electron/package.json
59
+ jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json
60
+ mv /tmp/package.json web/package.json
61
+ jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "bucket": "${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }}", "region": "auto", "endpoint": "https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com", "path": "${{ inputs.cloudflare_r2_path }}", "channel": "latest"}]' electron/package.json > /tmp/package.json
62
+ mv /tmp/package.json electron/package.json
63
+ cat electron/package.json
64
+
65
+ - name: Update app version base on tag
66
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
67
+ run: |
68
+ if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
69
+ echo "Error: Tag is not valid!"
70
+ exit 1
71
+ fi
72
+ jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
73
+ mv /tmp/package.json electron/package.json
74
+ jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json
75
+ mv /tmp/package.json web/package.json
76
+ env:
77
+ VERSION_TAG: ${{ inputs.new_version }}
78
+
79
+ - name: Build and publish app to cloudflare r2 or github artifactory
80
+ if: inputs.public_provider != 'github'
81
+ run: |
82
+ # check public_provider is true or not
83
+ echo "public_provider is ${{ inputs.public_provider }}"
84
+ if [ "${{ inputs.public_provider }}" == "none" ]; then
85
+ make build
86
+ else
87
+ make build-and-publish
88
+ fi
89
+ env:
90
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
91
+ AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }}
92
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }}
93
+ AWS_EC2_METADATA_DISABLED: "true"
94
+
95
+ - name: Build and publish app to github
96
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
97
+ run: |
98
+ make build-and-publish
99
+ env:
100
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
101
+ ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }}
102
+ ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }}
103
+
104
+ - name: Upload Artifact .deb file
105
+ if: inputs.public_provider != 'github'
106
+ uses: actions/upload-artifact@v2
107
+ with:
108
+ name: jan-linux-amd64-${{ inputs.new_version }}-deb
109
+ path: ./electron/dist/*.deb
110
+
111
+ - name: Upload Artifact .AppImage file
112
+ if: inputs.public_provider != 'github'
113
+ uses: actions/upload-artifact@v2
114
+ with:
115
+ name: jan-linux-amd64-${{ inputs.new_version }}-AppImage
116
+ path: ./electron/dist/*.AppImage
.github/workflows/template-build-macos-arm64.yml ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: build-macos
2
+ on:
3
+ workflow_call:
4
+ inputs:
5
+ ref:
6
+ required: true
7
+ type: string
8
+ default: 'refs/heads/main'
9
+ public_provider:
10
+ required: true
11
+ type: string
12
+ default: none
13
+ description: 'none: build only, github: build and publish to github, cloudflare: build and publish to cloudflare'
14
+ new_version:
15
+ required: true
16
+ type: string
17
+ default: ''
18
+ cloudflare_r2_path:
19
+ required: false
20
+ type: string
21
+ default: '/latest/'
22
+ secrets:
23
+ CLOUDFLARE_R2_BUCKET_NAME:
24
+ required: false
25
+ CLOUDFLARE_R2_ACCESS_KEY_ID:
26
+ required: false
27
+ CLOUDFLARE_R2_SECRET_ACCESS_KEY:
28
+ required: false
29
+ CLOUDFLARE_ACCOUNT_ID:
30
+ required: false
31
+ CODE_SIGN_P12_BASE64:
32
+ required: false
33
+ CODE_SIGN_P12_PASSWORD:
34
+ required: false
35
+ APPLE_ID:
36
+ required: false
37
+ APPLE_APP_SPECIFIC_PASSWORD:
38
+ required: false
39
+ DEVELOPER_ID:
40
+ required: false
41
+
42
+ jobs:
43
+ build-macos:
44
+ runs-on: macos-latest
45
+ environment: production
46
+ permissions:
47
+ contents: write
48
+ steps:
49
+ - name: Getting the repo
50
+ uses: actions/checkout@v3
51
+ with:
52
+ ref: ${{ inputs.ref }}
53
+
54
+ - name: Installing node
55
+ uses: actions/setup-node@v1
56
+ with:
57
+ node-version: 20
58
+
59
+ - name: Install jq
60
+ uses: dcarbone/install-jq-action@v2.0.1
61
+
62
+ - name: Update app version based on latest release tag with build number
63
+ if: inputs.public_provider != 'github'
64
+ run: |
65
+ echo "Version: ${{ inputs.new_version }}"
66
+ # Update the version in electron/package.json
67
+ jq --arg version "${{ inputs.new_version }}" '.version = $version' electron/package.json > /tmp/package.json
68
+ mv /tmp/package.json electron/package.json
69
+
70
+ jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json
71
+ mv /tmp/package.json web/package.json
72
+
73
+ jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "bucket": "${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }}", "region": "auto", "endpoint": "https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com", "path": "${{ inputs.cloudflare_r2_path }}", "channel": "latest"}]' electron/package.json > /tmp/package.json
74
+ mv /tmp/package.json electron/package.json
75
+
76
+ jq --arg teamid "${{ secrets.APPLE_TEAM_ID }}" '.build.mac.notarize.teamId = $teamid' electron/package.json > /tmp/package.json
77
+ mv /tmp/package.json electron/package.json
78
+
79
+ cat electron/package.json
80
+
81
+ - name: Update app version base on tag
82
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
83
+ run: |
84
+ if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
85
+ echo "Error: Tag is not valid!"
86
+ exit 1
87
+ fi
88
+ jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
89
+ mv /tmp/package.json electron/package.json
90
+ jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json
91
+ mv /tmp/package.json web/package.json
92
+ jq --arg teamid "${{ secrets.APPLE_TEAM_ID }}" '.build.mac.notarize.teamId = $teamid' electron/package.json > /tmp/package.json
93
+ mv /tmp/package.json electron/package.json
94
+ cat electron/package.json
95
+ env:
96
+ VERSION_TAG: ${{ inputs.new_version }}
97
+
98
+ - name: Get Cer for code signing
99
+ run: base64 -d <<< "$CODE_SIGN_P12_BASE64" > /tmp/codesign.p12
100
+ shell: bash
101
+ env:
102
+ CODE_SIGN_P12_BASE64: ${{ secrets.CODE_SIGN_P12_BASE64 }}
103
+
104
+ - uses: apple-actions/import-codesign-certs@v2
105
+ continue-on-error: true
106
+ with:
107
+ p12-file-base64: ${{ secrets.CODE_SIGN_P12_BASE64 }}
108
+ p12-password: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
109
+
110
+ - name: Build and publish app to cloudflare r2 or github artifactory
111
+ if: inputs.public_provider != 'github'
112
+ run: |
113
+ # check public_provider is true or not
114
+ echo "public_provider is ${{ inputs.public_provider }}"
115
+ if [ "${{ inputs.public_provider }}" == "none" ]; then
116
+ make build
117
+ else
118
+ make build-and-publish
119
+ fi
120
+ env:
121
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
122
+ CSC_LINK: "/tmp/codesign.p12"
123
+ CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
124
+ CSC_IDENTITY_AUTO_DISCOVERY: "true"
125
+ APPLE_ID: ${{ secrets.APPLE_ID }}
126
+ APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
127
+ APP_PATH: "."
128
+ DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }}
129
+ AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }}
130
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }}
131
+ AWS_DEFAULT_REGION: auto
132
+ AWS_EC2_METADATA_DISABLED: "true"
133
+
134
+ - name: Build and publish app to github
135
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
136
+ run: |
137
+ make build-and-publish
138
+ env:
139
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
140
+ CSC_LINK: "/tmp/codesign.p12"
141
+ CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
142
+ CSC_IDENTITY_AUTO_DISCOVERY: "true"
143
+ APPLE_ID: ${{ secrets.APPLE_ID }}
144
+ APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
145
+ APP_PATH: "."
146
+ DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }}
147
+ ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }}
148
+ ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }}
149
+
150
+ - name: Upload Artifact
151
+ if: inputs.public_provider != 'github'
152
+ uses: actions/upload-artifact@v2
153
+ with:
154
+ name: jan-mac-arm64-${{ inputs.new_version }}
155
+ path: ./electron/dist/jan-mac-arm64-${{ inputs.new_version }}.dmg
156
+
157
+ - name: Upload Artifact
158
+ uses: actions/upload-artifact@v2
159
+ with:
160
+ name: latest-mac-arm64
161
+ path: ./electron/dist/latest-mac.yml
.github/workflows/template-build-macos-x64.yml ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: build-macos
2
+ on:
3
+ workflow_call:
4
+ inputs:
5
+ ref:
6
+ required: true
7
+ type: string
8
+ default: 'refs/heads/main'
9
+ public_provider:
10
+ required: true
11
+ type: string
12
+ default: none
13
+ description: 'none: build only, github: build and publish to github, cloudflare: build and publish to cloudflare'
14
+ new_version:
15
+ required: true
16
+ type: string
17
+ default: ''
18
+ cloudflare_r2_path:
19
+ required: false
20
+ type: string
21
+ default: '/latest/'
22
+ secrets:
23
+ CLOUDFLARE_R2_BUCKET_NAME:
24
+ required: false
25
+ CLOUDFLARE_R2_ACCESS_KEY_ID:
26
+ required: false
27
+ CLOUDFLARE_R2_SECRET_ACCESS_KEY:
28
+ required: false
29
+ CLOUDFLARE_ACCOUNT_ID:
30
+ required: false
31
+ CODE_SIGN_P12_BASE64:
32
+ required: false
33
+ CODE_SIGN_P12_PASSWORD:
34
+ required: false
35
+ APPLE_ID:
36
+ required: false
37
+ APPLE_APP_SPECIFIC_PASSWORD:
38
+ required: false
39
+ DEVELOPER_ID:
40
+ required: false
41
+
42
+ jobs:
43
+ build-macos:
44
+ runs-on: macos-13
45
+ environment: production
46
+ permissions:
47
+ contents: write
48
+ steps:
49
+ - name: Getting the repo
50
+ uses: actions/checkout@v3
51
+ with:
52
+ ref: ${{ inputs.ref }}
53
+
54
+ - name: Installing node
55
+ uses: actions/setup-node@v1
56
+ with:
57
+ node-version: 20
58
+
59
+ - name: Install jq
60
+ uses: dcarbone/install-jq-action@v2.0.1
61
+
62
+ - name: Update app version based on latest release tag with build number
63
+ if: inputs.public_provider != 'github'
64
+ run: |
65
+ echo "Version: ${{ inputs.new_version }}"
66
+ # Update the version in electron/package.json
67
+ jq --arg version "${{ inputs.new_version }}" '.version = $version' electron/package.json > /tmp/package.json
68
+ mv /tmp/package.json electron/package.json
69
+
70
+ jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json
71
+ mv /tmp/package.json web/package.json
72
+
73
+ jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "bucket": "${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }}", "region": "auto", "endpoint": "https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com", "path": "${{ inputs.cloudflare_r2_path }}", "channel": "latest"}]' electron/package.json > /tmp/package.json
74
+ mv /tmp/package.json electron/package.json
75
+
76
+ jq --arg teamid "${{ secrets.APPLE_TEAM_ID }}" '.build.mac.notarize.teamId = $teamid' electron/package.json > /tmp/package.json
77
+ mv /tmp/package.json electron/package.json
78
+
79
+ cat electron/package.json
80
+
81
+ - name: Update app version base on tag
82
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
83
+ run: |
84
+ if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
85
+ echo "Error: Tag is not valid!"
86
+ exit 1
87
+ fi
88
+ jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
89
+ mv /tmp/package.json electron/package.json
90
+ jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json
91
+ mv /tmp/package.json web/package.json
92
+ jq --arg teamid "${{ secrets.APPLE_TEAM_ID }}" '.build.mac.notarize.teamId = $teamid' electron/package.json > /tmp/package.json
93
+ mv /tmp/package.json electron/package.json
94
+ cat electron/package.json
95
+ env:
96
+ VERSION_TAG: ${{ inputs.new_version }}
97
+
98
+ - name: Get Cer for code signing
99
+ run: base64 -d <<< "$CODE_SIGN_P12_BASE64" > /tmp/codesign.p12
100
+ shell: bash
101
+ env:
102
+ CODE_SIGN_P12_BASE64: ${{ secrets.CODE_SIGN_P12_BASE64 }}
103
+
104
+ - uses: apple-actions/import-codesign-certs@v2
105
+ continue-on-error: true
106
+ with:
107
+ p12-file-base64: ${{ secrets.CODE_SIGN_P12_BASE64 }}
108
+ p12-password: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
109
+
110
+ - name: Build and publish app to cloudflare r2 or github artifactory
111
+ if: inputs.public_provider != 'github'
112
+ run: |
113
+ # check public_provider is true or not
114
+ echo "public_provider is ${{ inputs.public_provider }}"
115
+ if [ "${{ inputs.public_provider }}" == "none" ]; then
116
+ make build
117
+ else
118
+ make build-and-publish
119
+ fi
120
+ env:
121
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
122
+ CSC_LINK: "/tmp/codesign.p12"
123
+ CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
124
+ CSC_IDENTITY_AUTO_DISCOVERY: "true"
125
+ APPLE_ID: ${{ secrets.APPLE_ID }}
126
+ APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
127
+ APP_PATH: "."
128
+ DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }}
129
+ AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }}
130
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }}
131
+ AWS_DEFAULT_REGION: auto
132
+ AWS_EC2_METADATA_DISABLED: "true"
133
+
134
+ - name: Build and publish app to github
135
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
136
+ run: |
137
+ make build-and-publish
138
+ env:
139
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
140
+ CSC_LINK: "/tmp/codesign.p12"
141
+ CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }}
142
+ CSC_IDENTITY_AUTO_DISCOVERY: "true"
143
+ APPLE_ID: ${{ secrets.APPLE_ID }}
144
+ APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
145
+ APP_PATH: "."
146
+ DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }}
147
+ ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }}
148
+ ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }}
149
+
150
+ - name: Upload Artifact
151
+ if: inputs.public_provider != 'github'
152
+ uses: actions/upload-artifact@v2
153
+ with:
154
+ name: jan-mac-x64-${{ inputs.new_version }}
155
+ path: ./electron/dist/jan-mac-x64-${{ inputs.new_version }}.dmg
156
+
157
+ - name: Upload Artifact
158
+ uses: actions/upload-artifact@v2
159
+ with:
160
+ name: latest-mac-x64
161
+ path: ./electron/dist/latest-mac.yml
.github/workflows/template-build-windows-x64.yml ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: build-windows-x64
2
+ on:
3
+ workflow_call:
4
+ inputs:
5
+ ref:
6
+ required: true
7
+ type: string
8
+ default: 'refs/heads/main'
9
+ public_provider:
10
+ required: true
11
+ type: string
12
+ default: none
13
+ description: 'none: build only, github: build and publish to github, cloudflare: build and publish to cloudflare'
14
+ new_version:
15
+ required: true
16
+ type: string
17
+ default: ''
18
+ cloudflare_r2_path:
19
+ required: false
20
+ type: string
21
+ default: '/latest/'
22
+ secrets:
23
+ CLOUDFLARE_R2_BUCKET_NAME:
24
+ required: false
25
+ CLOUDFLARE_R2_ACCESS_KEY_ID:
26
+ required: false
27
+ CLOUDFLARE_R2_SECRET_ACCESS_KEY:
28
+ required: false
29
+ CLOUDFLARE_ACCOUNT_ID:
30
+ required: false
31
+ AZURE_KEY_VAULT_URI:
32
+ required: false
33
+ AZURE_CLIENT_ID:
34
+ required: false
35
+ AZURE_TENANT_ID:
36
+ required: false
37
+ AZURE_CLIENT_SECRET:
38
+ required: false
39
+ AZURE_CERT_NAME:
40
+ required: false
41
+
42
+ jobs:
43
+ build-windows-x64:
44
+ runs-on: windows-latest
45
+ permissions:
46
+ contents: write
47
+ steps:
48
+ - name: Getting the repo
49
+ uses: actions/checkout@v3
50
+ with:
51
+ ref: ${{ inputs.ref }}
52
+
53
+ - name: Installing node
54
+ uses: actions/setup-node@v1
55
+ with:
56
+ node-version: 20
57
+
58
+ - name: Install jq
59
+ uses: dcarbone/install-jq-action@v2.0.1
60
+
61
+ - name: Update app version base on tag
62
+ if: inputs.public_provider != 'github'
63
+ id: version_update
64
+ shell: bash
65
+ run: |
66
+ echo "Version: ${{ inputs.new_version }}"
67
+ # Update the version in electron/package.json
68
+ jq --arg version "${{ inputs.new_version }}" '.version = $version' electron/package.json > /tmp/package.json
69
+ mv /tmp/package.json electron/package.json
70
+
71
+ jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json
72
+ mv /tmp/package.json web/package.json
73
+
74
+ jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "bucket": "${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }}", "region": "auto", "endpoint": "https://${{ secrets.CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com", "path": "${{ inputs.cloudflare_r2_path }}", "channel": "latest"}]' electron/package.json > /tmp/package.json
75
+ mv /tmp/package.json electron/package.json
76
+
77
+ jq '.build.win.sign = "./sign.js"' electron/package.json > /tmp/package.json
78
+ mv /tmp/package.json electron/package.json
79
+ cat electron/package.json
80
+
81
+ - name: Update app version base on tag
82
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
83
+ shell: bash
84
+ run: |
85
+ if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
86
+ echo "Error: Tag is not valid!"
87
+ exit 1
88
+ fi
89
+ jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json
90
+ mv /tmp/package.json electron/package.json
91
+ jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json
92
+ mv /tmp/package.json web/package.json
93
+ jq '.build.win.sign = "./sign.js"' electron/package.json > /tmp/package.json
94
+ mv /tmp/package.json electron/package.json
95
+ env:
96
+ VERSION_TAG: ${{ inputs.new_version }}
97
+
98
+ - name: Install AzureSignTool
99
+ run: |
100
+ dotnet tool install --global AzureSignTool
101
+
102
+ - name: Build and publish app to cloudflare r2 or github artifactory
103
+ shell: bash
104
+ if: inputs.public_provider != 'github'
105
+ run: |
106
+ # check public_provider is true or not
107
+ echo "public_provider is ${{ inputs.public_provider }}"
108
+ if [ "${{ inputs.public_provider }}" == "none" ]; then
109
+ make build
110
+ else
111
+ make build-and-publish
112
+ fi
113
+ env:
114
+ AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }}
115
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
116
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
117
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
118
+ AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }}
119
+ AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }}
120
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }}
121
+ AWS_DEFAULT_REGION: auto
122
+ AWS_EC2_METADATA_DISABLED: "true"
123
+
124
+ - name: Build app and publish app to github
125
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github'
126
+ run: |
127
+ make build-and-publish
128
+ env:
129
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
130
+ ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }}
131
+ ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }}
132
+ AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }}
133
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
134
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
135
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
136
+ AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }}
137
+
138
+ - name: Upload Artifact
139
+ if: inputs.public_provider != 'github'
140
+ uses: actions/upload-artifact@v2
141
+ with:
142
+ name: jan-win-x64-${{ inputs.new_version }}
143
+ path: ./electron/dist/*.exe
144
+
.github/workflows/template-get-update-version.yml ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: get-update-version
2
+ on:
3
+ workflow_call:
4
+ outputs:
5
+ new_version:
6
+ description: 'The new version of the app'
7
+ value: ${{ jobs.get-update-version.outputs.new_version }}
8
+
9
+ jobs:
10
+ get-update-version:
11
+ runs-on: ubuntu-latest
12
+ environment: production
13
+ outputs:
14
+ new_version: ${{ steps.version_update.outputs.new_version }}
15
+ steps:
16
+ - name: Install jq
17
+ uses: dcarbone/install-jq-action@v2.0.1
18
+
19
+ - name: Get tag
20
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
21
+ id: tag
22
+ uses: dawidd6/action-get-tag@v1
23
+
24
+ - name: Update app version based on latest release tag with build number
25
+ id: version_update
26
+ run: |
27
+ # Function to get the latest release tag
28
+ get_latest_tag() {
29
+ local retries=0
30
+ local max_retries=3
31
+ local tag
32
+ while [ $retries -lt $max_retries ]; do
33
+ tag=$(curl -s https://api.github.com/repos/janhq/jan/releases/latest | jq -r .tag_name)
34
+ if [ -n "$tag" ] && [ "$tag" != "null" ]; then
35
+ echo $tag
36
+ return
37
+ else
38
+ let retries++
39
+ echo "Retrying... ($retries/$max_retries)"
40
+ sleep 2
41
+ fi
42
+ done
43
+ echo "Failed to fetch latest tag after $max_retries attempts."
44
+ exit 1
45
+ }
46
+
47
+ if ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}; then
48
+ echo "Tag detected, set output follow tag"
49
+ echo "::set-output name=new_version::${{ steps.tag.outputs.tag }}"
50
+ else
51
+ # Get the latest release tag from GitHub API
52
+ LATEST_TAG=$(get_latest_tag)
53
+
54
+ # Remove the 'v' and append the build number to the version
55
+ new_version="${LATEST_TAG#v}-${GITHUB_RUN_NUMBER}"
56
+ echo "New version: $new_version"
57
+ echo "::set-output name=new_version::$new_version"
58
+ fi
.github/workflows/template-noti-discord-and-update-url-readme.yml ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: noti-discord-and-update-url-readme
2
+ on:
3
+ workflow_call:
4
+ inputs:
5
+ ref:
6
+ required: true
7
+ type: string
8
+ default: 'refs/heads/main'
9
+ build_reason:
10
+ required: true
11
+ type: string
12
+ default: 'Nightly'
13
+ push_to_branch:
14
+ required: true
15
+ type: string
16
+ default: 'main'
17
+ new_version:
18
+ required: true
19
+ type: string
20
+ default: ''
21
+ # secrets:
22
+ # PAT_SERVICE_ACCOUNT:
23
+ # required: false
24
+ # DISCORD_WEBHOOK:
25
+ # required: false
26
+
27
+ jobs:
28
+ noti-discord-and-update-url-readme:
29
+ environment: production
30
+ runs-on: ubuntu-latest
31
+ permissions:
32
+ contents: write
33
+ steps:
34
+ - name: Checkout code
35
+ uses: actions/checkout@v3
36
+ with:
37
+ fetch-depth: "0"
38
+ token: ${{ secrets.PAT_SERVICE_ACCOUNT }}
39
+ ref: ${{ inputs.ref }}
40
+
41
+ - name: Set version to environment variable
42
+ run: |
43
+ echo "VERSION=${{ inputs.new_version }}" >> $GITHUB_ENV
44
+
45
+ - name: Notify Discord
46
+ uses: Ilshidur/action-discord@master
47
+ with:
48
+ args: |
49
+ Jan App ${{ inputs.build_reason }} build artifact version {{ VERSION }}:
50
+ - Windows: https://delta.jan.ai/latest/jan-win-x64-{{ VERSION }}.exe
51
+ - macOS Intel: https://delta.jan.ai/latest/jan-mac-x64-{{ VERSION }}.dmg
52
+ - macOS Apple Silicon: https://delta.jan.ai/latest/jan-mac-arm64-{{ VERSION }}.dmg
53
+ - Linux Deb: https://delta.jan.ai/latest/jan-linux-amd64-{{ VERSION }}.deb
54
+ - Linux AppImage: https://delta.jan.ai/latest/jan-linux-x86_64-{{ VERSION }}.AppImage
55
+ - Github action run: https://github.com/janhq/jan/actions/runs/{{ GITHUB_RUN_ID }}
56
+ env:
57
+ DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
.gitignore ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .vscode
2
+ .idea
3
+ .env
4
+ .idea
5
+
6
+ # Jan inference
7
+ error.log
8
+ node_modules
9
+ *.tgz
10
+ !charts/server/charts/*.tgz
11
+ yarn.lock
12
+ dist
13
+ build
14
+ .DS_Store
15
+ electron/renderer
16
+ electron/models
17
+ electron/docs
18
+ electron/engines
19
+ electron/themes
20
+ electron/playwright-report
21
+ server/pre-install
22
+ package-lock.json
23
+
24
+ *.log
25
+ core/lib/**
26
+
27
+ # Nitro binary files
28
+ extensions/*-extension/bin/*/nitro
29
+ extensions/*-extension/bin/*/*.metal
30
+ extensions/*-extension/bin/*/*.exe
31
+ extensions/*-extension/bin/*/*.dll
32
+ extensions/*-extension/bin/*/*.exp
33
+ extensions/*-extension/bin/*/*.lib
34
+ extensions/*-extension/bin/saved-*
35
+ extensions/*-extension/bin/*.tar.gz
36
+ extensions/*-extension/bin/vulkaninfoSDK.exe
37
+ extensions/*-extension/bin/vulkaninfo
38
+
39
+
40
+ # Turborepo
41
+ .turbo
.husky/pre-commit ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ npx pretty-quick --staged
.prettierignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ .next/
2
+ node_modules/
3
+ dist/
4
+ *.hbs
5
+ *.mdx
.prettierrc ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "semi": false,
3
+ "singleQuote": true,
4
+ "quoteProps": "consistent",
5
+ "trailingComma": "es5",
6
+ "endOfLine": "auto"
7
+ }
Dockerfile ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:20-bookworm AS base
2
+
3
+ # 1. Install dependencies only when needed
4
+ FROM base AS builder
5
+
6
+ # Install g++ 11
7
+ RUN apt update && apt install -y gcc-11 g++-11 cpp-11 jq xsel && rm -rf /var/lib/apt/lists/*
8
+
9
+ WORKDIR /app
10
+
11
+ # Install dependencies based on the preferred package manager
12
+ COPY . ./
13
+
14
+ RUN export NITRO_VERSION=$(cat extensions/inference-nitro-extension/bin/version.txt) && \
15
+ jq --arg nitroVersion $NITRO_VERSION '(.scripts."downloadnitro:linux" | gsub("\\${NITRO_VERSION}"; $nitroVersion)) | gsub("\r"; "")' extensions/inference-nitro-extension/package.json > /tmp/newcommand.txt && export NEW_COMMAND=$(sed 's/^"//;s/"$//' /tmp/newcommand.txt) && jq --arg newCommand "$NEW_COMMAND" '.scripts."downloadnitro:linux" = $newCommand' extensions/inference-nitro-extension/package.json > /tmp/package.json && mv /tmp/package.json extensions/inference-nitro-extension/package.json
16
+ RUN make install-and-build
17
+
18
+ # # 2. Rebuild the source code only when needed
19
+ FROM base AS runner
20
+
21
+ # Install g++ 11
22
+ RUN apt update && apt install -y gcc-11 g++-11 cpp-11 jq xsel && rm -rf /var/lib/apt/lists/*
23
+
24
+ WORKDIR /app
25
+
26
+ # Copy the package.json and yarn.lock of root yarn space to leverage Docker cache
27
+ COPY --from=builder /app/package.json ./package.json
28
+ COPY --from=builder /app/node_modules ./node_modules/
29
+ COPY --from=builder /app/yarn.lock ./yarn.lock
30
+
31
+ # Copy the package.json, yarn.lock, and build output of server yarn space to leverage Docker cache
32
+ COPY --from=builder /app/core ./core/
33
+ COPY --from=builder /app/server ./server/
34
+ RUN cd core && yarn install && yarn run build
35
+ RUN yarn workspace @janhq/server install && yarn workspace @janhq/server build
36
+ COPY --from=builder /app/docs/openapi ./docs/openapi/
37
+
38
+ # Copy pre-install dependencies
39
+ COPY --from=builder /app/pre-install ./pre-install/
40
+
41
+ # Copy the package.json, yarn.lock, and output of web yarn space to leverage Docker cache
42
+ COPY --from=builder /app/joi ./joi/
43
+ COPY --from=builder /app/web ./web/
44
+
45
+ RUN yarn workspace @janhq/joi install && yarn workspace @janhq/joi build
46
+ RUN yarn workspace @janhq/web install
47
+
48
+ RUN npm install -g serve@latest
49
+
50
+ EXPOSE 1337 3000 3928
51
+
52
+ ENV JAN_API_HOST 0.0.0.0
53
+ ENV JAN_API_PORT 1337
54
+
55
+ ENV API_BASE_URL http://localhost:1337
56
+
57
+ CMD ["sh", "-c", "export NODE_ENV=production && yarn workspace @janhq/web build && cd web && npx serve out & cd server && node build/main.js"]
58
+
59
+ # docker build -t jan .
60
+ # docker run -p 1337:1337 -p 3000:3000 -p 3928:3928 jan
Dockerfile.gpu ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Please change the base image to the appropriate CUDA version base on NVIDIA Driver Compatibility
2
+ # Run nvidia-smi to check the CUDA version and the corresponding driver version
3
+ # Then update the base image to the appropriate CUDA version refer https://catalog.ngc.nvidia.com/orgs/nvidia/containers/cuda/tags
4
+
5
+ FROM nvidia/cuda:12.2.0-runtime-ubuntu22.04 AS base
6
+
7
+ # 1. Install dependencies only when needed
8
+ FROM base AS builder
9
+
10
+ # Install g++ 11
11
+ RUN apt update && apt install -y gcc-11 g++-11 cpp-11 jq xsel curl gnupg make python3-dev && curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt install nodejs -y && rm -rf /var/lib/apt/lists/*
12
+
13
+ # Update alternatives for GCC and related tools
14
+ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 110 \
15
+ --slave /usr/bin/g++ g++ /usr/bin/g++-11 \
16
+ --slave /usr/bin/gcov gcov /usr/bin/gcov-11 \
17
+ --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-11 \
18
+ --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-11 && \
19
+ update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-11 110
20
+
21
+ RUN npm install -g yarn
22
+
23
+ WORKDIR /app
24
+
25
+ # Install dependencies based on the preferred package manager
26
+ COPY . ./
27
+
28
+ RUN export NITRO_VERSION=$(cat extensions/inference-nitro-extension/bin/version.txt) && \
29
+ jq --arg nitroVersion $NITRO_VERSION '(.scripts."downloadnitro:linux" | gsub("\\${NITRO_VERSION}"; $nitroVersion)) | gsub("\r"; "")' extensions/inference-nitro-extension/package.json > /tmp/newcommand.txt && export NEW_COMMAND=$(sed 's/^"//;s/"$//' /tmp/newcommand.txt) && jq --arg newCommand "$NEW_COMMAND" '.scripts."downloadnitro:linux" = $newCommand' extensions/inference-nitro-extension/package.json > /tmp/package.json && mv /tmp/package.json extensions/inference-nitro-extension/package.json
30
+ RUN make install-and-build
31
+
32
+ # # 2. Rebuild the source code only when needed
33
+ FROM base AS runner
34
+
35
+ # Install g++ 11
36
+ RUN apt update && apt install -y gcc-11 g++-11 cpp-11 jq xsel curl gnupg make python3-dev && curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt-get install nodejs -y && rm -rf /var/lib/apt/lists/*
37
+
38
+ # Update alternatives for GCC and related tools
39
+ RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 110 \
40
+ --slave /usr/bin/g++ g++ /usr/bin/g++-11 \
41
+ --slave /usr/bin/gcov gcov /usr/bin/gcov-11 \
42
+ --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-11 \
43
+ --slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-11 && \
44
+ update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-11 110
45
+
46
+ RUN npm install -g yarn
47
+
48
+ WORKDIR /app
49
+
50
+ # Copy the package.json and yarn.lock of root yarn space to leverage Docker cache
51
+ COPY --from=builder /app/package.json ./package.json
52
+ COPY --from=builder /app/node_modules ./node_modules/
53
+ COPY --from=builder /app/yarn.lock ./yarn.lock
54
+
55
+ # Copy the package.json, yarn.lock, and build output of server yarn space to leverage Docker cache
56
+ COPY --from=builder /app/core ./core/
57
+ COPY --from=builder /app/server ./server/
58
+ RUN cd core && yarn install && yarn run build
59
+ RUN yarn workspace @janhq/server install && yarn workspace @janhq/server build
60
+ COPY --from=builder /app/docs/openapi ./docs/openapi/
61
+
62
+ # Copy pre-install dependencies
63
+ COPY --from=builder /app/pre-install ./pre-install/
64
+
65
+ # Copy the package.json, yarn.lock, and output of web yarn space to leverage Docker cache
66
+ COPY --from=builder /app/joi ./joi/
67
+ COPY --from=builder /app/web ./web/
68
+
69
+ RUN yarn workspace @janhq/joi install && yarn workspace @janhq/joi build
70
+ RUN yarn workspace @janhq/web install
71
+
72
+ RUN npm install -g serve@latest
73
+
74
+ EXPOSE 1337 3000 3928
75
+
76
+ ENV LD_LIBRARY_PATH=/usr/local/cuda/targets/x86_64-linux/lib:/usr/local/cuda-12.0/compat${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
77
+
78
+ ENV JAN_API_HOST 0.0.0.0
79
+ ENV JAN_API_PORT 1337
80
+
81
+ ENV API_BASE_URL http://localhost:1337
82
+
83
+ CMD ["sh", "-c", "export NODE_ENV=production && yarn workspace @janhq/web build && cd web && npx serve out & cd server && node build/main.js"]
84
+
85
+ # pre-requisites: nvidia-docker
86
+ # docker build -t jan-gpu . -f Dockerfile.gpu
87
+ # docker run -p 1337:1337 -p 3000:3000 -p 3928:3928 --gpus all jan-gpu
LICENSE ADDED
@@ -0,0 +1,660 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # GNU AFFERO GENERAL PUBLIC LICENSE
2
+
3
+ Version 3, 19 November 2007
4
+
5
+ Copyright (C) 2007 Free Software Foundation, Inc.
6
+ <https://fsf.org/>
7
+
8
+ Everyone is permitted to copy and distribute verbatim copies of this
9
+ license document, but changing it is not allowed.
10
+
11
+ ## Preamble
12
+
13
+ The GNU Affero General Public License is a free, copyleft license for
14
+ software and other kinds of works, specifically designed to ensure
15
+ cooperation with the community in the case of network server software.
16
+
17
+ The licenses for most software and other practical works are designed
18
+ to take away your freedom to share and change the works. By contrast,
19
+ our General Public Licenses are intended to guarantee your freedom to
20
+ share and change all versions of a program--to make sure it remains
21
+ free software for all its users.
22
+
23
+ When we speak of free software, we are referring to freedom, not
24
+ price. Our General Public Licenses are designed to make sure that you
25
+ have the freedom to distribute copies of free software (and charge for
26
+ them if you wish), that you receive source code or can get it if you
27
+ want it, that you can change the software or use pieces of it in new
28
+ free programs, and that you know you can do these things.
29
+
30
+ Developers that use our General Public Licenses protect your rights
31
+ with two steps: (1) assert copyright on the software, and (2) offer
32
+ you this License which gives you legal permission to copy, distribute
33
+ and/or modify the software.
34
+
35
+ A secondary benefit of defending all users' freedom is that
36
+ improvements made in alternate versions of the program, if they
37
+ receive widespread use, become available for other developers to
38
+ incorporate. Many developers of free software are heartened and
39
+ encouraged by the resulting cooperation. However, in the case of
40
+ software used on network servers, this result may fail to come about.
41
+ The GNU General Public License permits making a modified version and
42
+ letting the public access it on a server without ever releasing its
43
+ source code to the public.
44
+
45
+ The GNU Affero General Public License is designed specifically to
46
+ ensure that, in such cases, the modified source code becomes available
47
+ to the community. It requires the operator of a network server to
48
+ provide the source code of the modified version running there to the
49
+ users of that server. Therefore, public use of a modified version, on
50
+ a publicly accessible server, gives the public access to the source
51
+ code of the modified version.
52
+
53
+ An older license, called the Affero General Public License and
54
+ published by Affero, was designed to accomplish similar goals. This is
55
+ a different license, not a version of the Affero GPL, but Affero has
56
+ released a new version of the Affero GPL which permits relicensing
57
+ under this license.
58
+
59
+ The precise terms and conditions for copying, distribution and
60
+ modification follow.
61
+
62
+ ## TERMS AND CONDITIONS
63
+
64
+ ### 0. Definitions.
65
+
66
+ "This License" refers to version 3 of the GNU Affero General Public
67
+ License.
68
+
69
+ "Copyright" also means copyright-like laws that apply to other kinds
70
+ of works, such as semiconductor masks.
71
+
72
+ "The Program" refers to any copyrightable work licensed under this
73
+ License. Each licensee is addressed as "you". "Licensees" and
74
+ "recipients" may be individuals or organizations.
75
+
76
+ To "modify" a work means to copy from or adapt all or part of the work
77
+ in a fashion requiring copyright permission, other than the making of
78
+ an exact copy. The resulting work is called a "modified version" of
79
+ the earlier work or a work "based on" the earlier work.
80
+
81
+ A "covered work" means either the unmodified Program or a work based
82
+ on the Program.
83
+
84
+ To "propagate" a work means to do anything with it that, without
85
+ permission, would make you directly or secondarily liable for
86
+ infringement under applicable copyright law, except executing it on a
87
+ computer or modifying a private copy. Propagation includes copying,
88
+ distribution (with or without modification), making available to the
89
+ public, and in some countries other activities as well.
90
+
91
+ To "convey" a work means any kind of propagation that enables other
92
+ parties to make or receive copies. Mere interaction with a user
93
+ through a computer network, with no transfer of a copy, is not
94
+ conveying.
95
+
96
+ An interactive user interface displays "Appropriate Legal Notices" to
97
+ the extent that it includes a convenient and prominently visible
98
+ feature that (1) displays an appropriate copyright notice, and (2)
99
+ tells the user that there is no warranty for the work (except to the
100
+ extent that warranties are provided), that licensees may convey the
101
+ work under this License, and how to view a copy of this License. If
102
+ the interface presents a list of user commands or options, such as a
103
+ menu, a prominent item in the list meets this criterion.
104
+
105
+ ### 1. Source Code.
106
+
107
+ The "source code" for a work means the preferred form of the work for
108
+ making modifications to it. "Object code" means any non-source form of
109
+ a work.
110
+
111
+ A "Standard Interface" means an interface that either is an official
112
+ standard defined by a recognized standards body, or, in the case of
113
+ interfaces specified for a particular programming language, one that
114
+ is widely used among developers working in that language.
115
+
116
+ The "System Libraries" of an executable work include anything, other
117
+ than the work as a whole, that (a) is included in the normal form of
118
+ packaging a Major Component, but which is not part of that Major
119
+ Component, and (b) serves only to enable use of the work with that
120
+ Major Component, or to implement a Standard Interface for which an
121
+ implementation is available to the public in source code form. A
122
+ "Major Component", in this context, means a major essential component
123
+ (kernel, window system, and so on) of the specific operating system
124
+ (if any) on which the executable work runs, or a compiler used to
125
+ produce the work, or an object code interpreter used to run it.
126
+
127
+ The "Corresponding Source" for a work in object code form means all
128
+ the source code needed to generate, install, and (for an executable
129
+ work) run the object code and to modify the work, including scripts to
130
+ control those activities. However, it does not include the work's
131
+ System Libraries, or general-purpose tools or generally available free
132
+ programs which are used unmodified in performing those activities but
133
+ which are not part of the work. For example, Corresponding Source
134
+ includes interface definition files associated with source files for
135
+ the work, and the source code for shared libraries and dynamically
136
+ linked subprograms that the work is specifically designed to require,
137
+ such as by intimate data communication or control flow between those
138
+ subprograms and other parts of the work.
139
+
140
+ The Corresponding Source need not include anything that users can
141
+ regenerate automatically from other parts of the Corresponding Source.
142
+
143
+ The Corresponding Source for a work in source code form is that same
144
+ work.
145
+
146
+ ### 2. Basic Permissions.
147
+
148
+ All rights granted under this License are granted for the term of
149
+ copyright on the Program, and are irrevocable provided the stated
150
+ conditions are met. This License explicitly affirms your unlimited
151
+ permission to run the unmodified Program. The output from running a
152
+ covered work is covered by this License only if the output, given its
153
+ content, constitutes a covered work. This License acknowledges your
154
+ rights of fair use or other equivalent, as provided by copyright law.
155
+
156
+ You may make, run and propagate covered works that you do not convey,
157
+ without conditions so long as your license otherwise remains in force.
158
+ You may convey covered works to others for the sole purpose of having
159
+ them make modifications exclusively for you, or provide you with
160
+ facilities for running those works, provided that you comply with the
161
+ terms of this License in conveying all material for which you do not
162
+ control copyright. Those thus making or running the covered works for
163
+ you must do so exclusively on your behalf, under your direction and
164
+ control, on terms that prohibit them from making any copies of your
165
+ copyrighted material outside their relationship with you.
166
+
167
+ Conveying under any other circumstances is permitted solely under the
168
+ conditions stated below. Sublicensing is not allowed; section 10 makes
169
+ it unnecessary.
170
+
171
+ ### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
172
+
173
+ No covered work shall be deemed part of an effective technological
174
+ measure under any applicable law fulfilling obligations under article
175
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
176
+ similar laws prohibiting or restricting circumvention of such
177
+ measures.
178
+
179
+ When you convey a covered work, you waive any legal power to forbid
180
+ circumvention of technological measures to the extent such
181
+ circumvention is effected by exercising rights under this License with
182
+ respect to the covered work, and you disclaim any intention to limit
183
+ operation or modification of the work as a means of enforcing, against
184
+ the work's users, your or third parties' legal rights to forbid
185
+ circumvention of technological measures.
186
+
187
+ ### 4. Conveying Verbatim Copies.
188
+
189
+ You may convey verbatim copies of the Program's source code as you
190
+ receive it, in any medium, provided that you conspicuously and
191
+ appropriately publish on each copy an appropriate copyright notice;
192
+ keep intact all notices stating that this License and any
193
+ non-permissive terms added in accord with section 7 apply to the code;
194
+ keep intact all notices of the absence of any warranty; and give all
195
+ recipients a copy of this License along with the Program.
196
+
197
+ You may charge any price or no price for each copy that you convey,
198
+ and you may offer support or warranty protection for a fee.
199
+
200
+ ### 5. Conveying Modified Source Versions.
201
+
202
+ You may convey a work based on the Program, or the modifications to
203
+ produce it from the Program, in the form of source code under the
204
+ terms of section 4, provided that you also meet all of these
205
+ conditions:
206
+
207
+ - a) The work must carry prominent notices stating that you modified
208
+ it, and giving a relevant date.
209
+ - b) The work must carry prominent notices stating that it is
210
+ released under this License and any conditions added under
211
+ section 7. This requirement modifies the requirement in section 4
212
+ to "keep intact all notices".
213
+ - c) You must license the entire work, as a whole, under this
214
+ License to anyone who comes into possession of a copy. This
215
+ License will therefore apply, along with any applicable section 7
216
+ additional terms, to the whole of the work, and all its parts,
217
+ regardless of how they are packaged. This License gives no
218
+ permission to license the work in any other way, but it does not
219
+ invalidate such permission if you have separately received it.
220
+ - d) If the work has interactive user interfaces, each must display
221
+ Appropriate Legal Notices; however, if the Program has interactive
222
+ interfaces that do not display Appropriate Legal Notices, your
223
+ work need not make them do so.
224
+
225
+ A compilation of a covered work with other separate and independent
226
+ works, which are not by their nature extensions of the covered work,
227
+ and which are not combined with it such as to form a larger program,
228
+ in or on a volume of a storage or distribution medium, is called an
229
+ "aggregate" if the compilation and its resulting copyright are not
230
+ used to limit the access or legal rights of the compilation's users
231
+ beyond what the individual works permit. Inclusion of a covered work
232
+ in an aggregate does not cause this License to apply to the other
233
+ parts of the aggregate.
234
+
235
+ ### 6. Conveying Non-Source Forms.
236
+
237
+ You may convey a covered work in object code form under the terms of
238
+ sections 4 and 5, provided that you also convey the machine-readable
239
+ Corresponding Source under the terms of this License, in one of these
240
+ ways:
241
+
242
+ - a) Convey the object code in, or embodied in, a physical product
243
+ (including a physical distribution medium), accompanied by the
244
+ Corresponding Source fixed on a durable physical medium
245
+ customarily used for software interchange.
246
+ - b) Convey the object code in, or embodied in, a physical product
247
+ (including a physical distribution medium), accompanied by a
248
+ written offer, valid for at least three years and valid for as
249
+ long as you offer spare parts or customer support for that product
250
+ model, to give anyone who possesses the object code either (1) a
251
+ copy of the Corresponding Source for all the software in the
252
+ product that is covered by this License, on a durable physical
253
+ medium customarily used for software interchange, for a price no
254
+ more than your reasonable cost of physically performing this
255
+ conveying of source, or (2) access to copy the Corresponding
256
+ Source from a network server at no charge.
257
+ - c) Convey individual copies of the object code with a copy of the
258
+ written offer to provide the Corresponding Source. This
259
+ alternative is allowed only occasionally and noncommercially, and
260
+ only if you received the object code with such an offer, in accord
261
+ with subsection 6b.
262
+ - d) Convey the object code by offering access from a designated
263
+ place (gratis or for a charge), and offer equivalent access to the
264
+ Corresponding Source in the same way through the same place at no
265
+ further charge. You need not require recipients to copy the
266
+ Corresponding Source along with the object code. If the place to
267
+ copy the object code is a network server, the Corresponding Source
268
+ may be on a different server (operated by you or a third party)
269
+ that supports equivalent copying facilities, provided you maintain
270
+ clear directions next to the object code saying where to find the
271
+ Corresponding Source. Regardless of what server hosts the
272
+ Corresponding Source, you remain obligated to ensure that it is
273
+ available for as long as needed to satisfy these requirements.
274
+ - e) Convey the object code using peer-to-peer transmission,
275
+ provided you inform other peers where the object code and
276
+ Corresponding Source of the work are being offered to the general
277
+ public at no charge under subsection 6d.
278
+
279
+ A separable portion of the object code, whose source code is excluded
280
+ from the Corresponding Source as a System Library, need not be
281
+ included in conveying the object code work.
282
+
283
+ A "User Product" is either (1) a "consumer product", which means any
284
+ tangible personal property which is normally used for personal,
285
+ family, or household purposes, or (2) anything designed or sold for
286
+ incorporation into a dwelling. In determining whether a product is a
287
+ consumer product, doubtful cases shall be resolved in favor of
288
+ coverage. For a particular product received by a particular user,
289
+ "normally used" refers to a typical or common use of that class of
290
+ product, regardless of the status of the particular user or of the way
291
+ in which the particular user actually uses, or expects or is expected
292
+ to use, the product. A product is a consumer product regardless of
293
+ whether the product has substantial commercial, industrial or
294
+ non-consumer uses, unless such uses represent the only significant
295
+ mode of use of the product.
296
+
297
+ "Installation Information" for a User Product means any methods,
298
+ procedures, authorization keys, or other information required to
299
+ install and execute modified versions of a covered work in that User
300
+ Product from a modified version of its Corresponding Source. The
301
+ information must suffice to ensure that the continued functioning of
302
+ the modified object code is in no case prevented or interfered with
303
+ solely because modification has been made.
304
+
305
+ If you convey an object code work under this section in, or with, or
306
+ specifically for use in, a User Product, and the conveying occurs as
307
+ part of a transaction in which the right of possession and use of the
308
+ User Product is transferred to the recipient in perpetuity or for a
309
+ fixed term (regardless of how the transaction is characterized), the
310
+ Corresponding Source conveyed under this section must be accompanied
311
+ by the Installation Information. But this requirement does not apply
312
+ if neither you nor any third party retains the ability to install
313
+ modified object code on the User Product (for example, the work has
314
+ been installed in ROM).
315
+
316
+ The requirement to provide Installation Information does not include a
317
+ requirement to continue to provide support service, warranty, or
318
+ updates for a work that has been modified or installed by the
319
+ recipient, or for the User Product in which it has been modified or
320
+ installed. Access to a network may be denied when the modification
321
+ itself materially and adversely affects the operation of the network
322
+ or violates the rules and protocols for communication across the
323
+ network.
324
+
325
+ Corresponding Source conveyed, and Installation Information provided,
326
+ in accord with this section must be in a format that is publicly
327
+ documented (and with an implementation available to the public in
328
+ source code form), and must require no special password or key for
329
+ unpacking, reading or copying.
330
+
331
+ ### 7. Additional Terms.
332
+
333
+ "Additional permissions" are terms that supplement the terms of this
334
+ License by making exceptions from one or more of its conditions.
335
+ Additional permissions that are applicable to the entire Program shall
336
+ be treated as though they were included in this License, to the extent
337
+ that they are valid under applicable law. If additional permissions
338
+ apply only to part of the Program, that part may be used separately
339
+ under those permissions, but the entire Program remains governed by
340
+ this License without regard to the additional permissions.
341
+
342
+ When you convey a copy of a covered work, you may at your option
343
+ remove any additional permissions from that copy, or from any part of
344
+ it. (Additional permissions may be written to require their own
345
+ removal in certain cases when you modify the work.) You may place
346
+ additional permissions on material, added by you to a covered work,
347
+ for which you have or can give appropriate copyright permission.
348
+
349
+ Notwithstanding any other provision of this License, for material you
350
+ add to a covered work, you may (if authorized by the copyright holders
351
+ of that material) supplement the terms of this License with terms:
352
+
353
+ - a) Disclaiming warranty or limiting liability differently from the
354
+ terms of sections 15 and 16 of this License; or
355
+ - b) Requiring preservation of specified reasonable legal notices or
356
+ author attributions in that material or in the Appropriate Legal
357
+ Notices displayed by works containing it; or
358
+ - c) Prohibiting misrepresentation of the origin of that material,
359
+ or requiring that modified versions of such material be marked in
360
+ reasonable ways as different from the original version; or
361
+ - d) Limiting the use for publicity purposes of names of licensors
362
+ or authors of the material; or
363
+ - e) Declining to grant rights under trademark law for use of some
364
+ trade names, trademarks, or service marks; or
365
+ - f) Requiring indemnification of licensors and authors of that
366
+ material by anyone who conveys the material (or modified versions
367
+ of it) with contractual assumptions of liability to the recipient,
368
+ for any liability that these contractual assumptions directly
369
+ impose on those licensors and authors.
370
+
371
+ All other non-permissive additional terms are considered "further
372
+ restrictions" within the meaning of section 10. If the Program as you
373
+ received it, or any part of it, contains a notice stating that it is
374
+ governed by this License along with a term that is a further
375
+ restriction, you may remove that term. If a license document contains
376
+ a further restriction but permits relicensing or conveying under this
377
+ License, you may add to a covered work material governed by the terms
378
+ of that license document, provided that the further restriction does
379
+ not survive such relicensing or conveying.
380
+
381
+ If you add terms to a covered work in accord with this section, you
382
+ must place, in the relevant source files, a statement of the
383
+ additional terms that apply to those files, or a notice indicating
384
+ where to find the applicable terms.
385
+
386
+ Additional terms, permissive or non-permissive, may be stated in the
387
+ form of a separately written license, or stated as exceptions; the
388
+ above requirements apply either way.
389
+
390
+ ### 8. Termination.
391
+
392
+ You may not propagate or modify a covered work except as expressly
393
+ provided under this License. Any attempt otherwise to propagate or
394
+ modify it is void, and will automatically terminate your rights under
395
+ this License (including any patent licenses granted under the third
396
+ paragraph of section 11).
397
+
398
+ However, if you cease all violation of this License, then your license
399
+ from a particular copyright holder is reinstated (a) provisionally,
400
+ unless and until the copyright holder explicitly and finally
401
+ terminates your license, and (b) permanently, if the copyright holder
402
+ fails to notify you of the violation by some reasonable means prior to
403
+ 60 days after the cessation.
404
+
405
+ Moreover, your license from a particular copyright holder is
406
+ reinstated permanently if the copyright holder notifies you of the
407
+ violation by some reasonable means, this is the first time you have
408
+ received notice of violation of this License (for any work) from that
409
+ copyright holder, and you cure the violation prior to 30 days after
410
+ your receipt of the notice.
411
+
412
+ Termination of your rights under this section does not terminate the
413
+ licenses of parties who have received copies or rights from you under
414
+ this License. If your rights have been terminated and not permanently
415
+ reinstated, you do not qualify to receive new licenses for the same
416
+ material under section 10.
417
+
418
+ ### 9. Acceptance Not Required for Having Copies.
419
+
420
+ You are not required to accept this License in order to receive or run
421
+ a copy of the Program. Ancillary propagation of a covered work
422
+ occurring solely as a consequence of using peer-to-peer transmission
423
+ to receive a copy likewise does not require acceptance. However,
424
+ nothing other than this License grants you permission to propagate or
425
+ modify any covered work. These actions infringe copyright if you do
426
+ not accept this License. Therefore, by modifying or propagating a
427
+ covered work, you indicate your acceptance of this License to do so.
428
+
429
+ ### 10. Automatic Licensing of Downstream Recipients.
430
+
431
+ Each time you convey a covered work, the recipient automatically
432
+ receives a license from the original licensors, to run, modify and
433
+ propagate that work, subject to this License. You are not responsible
434
+ for enforcing compliance by third parties with this License.
435
+
436
+ An "entity transaction" is a transaction transferring control of an
437
+ organization, or substantially all assets of one, or subdividing an
438
+ organization, or merging organizations. If propagation of a covered
439
+ work results from an entity transaction, each party to that
440
+ transaction who receives a copy of the work also receives whatever
441
+ licenses to the work the party's predecessor in interest had or could
442
+ give under the previous paragraph, plus a right to possession of the
443
+ Corresponding Source of the work from the predecessor in interest, if
444
+ the predecessor has it or can get it with reasonable efforts.
445
+
446
+ You may not impose any further restrictions on the exercise of the
447
+ rights granted or affirmed under this License. For example, you may
448
+ not impose a license fee, royalty, or other charge for exercise of
449
+ rights granted under this License, and you may not initiate litigation
450
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
451
+ any patent claim is infringed by making, using, selling, offering for
452
+ sale, or importing the Program or any portion of it.
453
+
454
+ ### 11. Patents.
455
+
456
+ A "contributor" is a copyright holder who authorizes use under this
457
+ License of the Program or a work on which the Program is based. The
458
+ work thus licensed is called the contributor's "contributor version".
459
+
460
+ A contributor's "essential patent claims" are all patent claims owned
461
+ or controlled by the contributor, whether already acquired or
462
+ hereafter acquired, that would be infringed by some manner, permitted
463
+ by this License, of making, using, or selling its contributor version,
464
+ but do not include claims that would be infringed only as a
465
+ consequence of further modification of the contributor version. For
466
+ purposes of this definition, "control" includes the right to grant
467
+ patent sublicenses in a manner consistent with the requirements of
468
+ this License.
469
+
470
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
471
+ patent license under the contributor's essential patent claims, to
472
+ make, use, sell, offer for sale, import and otherwise run, modify and
473
+ propagate the contents of its contributor version.
474
+
475
+ In the following three paragraphs, a "patent license" is any express
476
+ agreement or commitment, however denominated, not to enforce a patent
477
+ (such as an express permission to practice a patent or covenant not to
478
+ sue for patent infringement). To "grant" such a patent license to a
479
+ party means to make such an agreement or commitment not to enforce a
480
+ patent against the party.
481
+
482
+ If you convey a covered work, knowingly relying on a patent license,
483
+ and the Corresponding Source of the work is not available for anyone
484
+ to copy, free of charge and under the terms of this License, through a
485
+ publicly available network server or other readily accessible means,
486
+ then you must either (1) cause the Corresponding Source to be so
487
+ available, or (2) arrange to deprive yourself of the benefit of the
488
+ patent license for this particular work, or (3) arrange, in a manner
489
+ consistent with the requirements of this License, to extend the patent
490
+ license to downstream recipients. "Knowingly relying" means you have
491
+ actual knowledge that, but for the patent license, your conveying the
492
+ covered work in a country, or your recipient's use of the covered work
493
+ in a country, would infringe one or more identifiable patents in that
494
+ country that you have reason to believe are valid.
495
+
496
+ If, pursuant to or in connection with a single transaction or
497
+ arrangement, you convey, or propagate by procuring conveyance of, a
498
+ covered work, and grant a patent license to some of the parties
499
+ receiving the covered work authorizing them to use, propagate, modify
500
+ or convey a specific copy of the covered work, then the patent license
501
+ you grant is automatically extended to all recipients of the covered
502
+ work and works based on it.
503
+
504
+ A patent license is "discriminatory" if it does not include within the
505
+ scope of its coverage, prohibits the exercise of, or is conditioned on
506
+ the non-exercise of one or more of the rights that are specifically
507
+ granted under this License. You may not convey a covered work if you
508
+ are a party to an arrangement with a third party that is in the
509
+ business of distributing software, under which you make payment to the
510
+ third party based on the extent of your activity of conveying the
511
+ work, and under which the third party grants, to any of the parties
512
+ who would receive the covered work from you, a discriminatory patent
513
+ license (a) in connection with copies of the covered work conveyed by
514
+ you (or copies made from those copies), or (b) primarily for and in
515
+ connection with specific products or compilations that contain the
516
+ covered work, unless you entered into that arrangement, or that patent
517
+ license was granted, prior to 28 March 2007.
518
+
519
+ Nothing in this License shall be construed as excluding or limiting
520
+ any implied license or other defenses to infringement that may
521
+ otherwise be available to you under applicable patent law.
522
+
523
+ ### 12. No Surrender of Others' Freedom.
524
+
525
+ If conditions are imposed on you (whether by court order, agreement or
526
+ otherwise) that contradict the conditions of this License, they do not
527
+ excuse you from the conditions of this License. If you cannot convey a
528
+ covered work so as to satisfy simultaneously your obligations under
529
+ this License and any other pertinent obligations, then as a
530
+ consequence you may not convey it at all. For example, if you agree to
531
+ terms that obligate you to collect a royalty for further conveying
532
+ from those to whom you convey the Program, the only way you could
533
+ satisfy both those terms and this License would be to refrain entirely
534
+ from conveying the Program.
535
+
536
+ ### 13. Remote Network Interaction; Use with the GNU General Public License.
537
+
538
+ Notwithstanding any other provision of this License, if you modify the
539
+ Program, your modified version must prominently offer all users
540
+ interacting with it remotely through a computer network (if your
541
+ version supports such interaction) an opportunity to receive the
542
+ Corresponding Source of your version by providing access to the
543
+ Corresponding Source from a network server at no charge, through some
544
+ standard or customary means of facilitating copying of software. This
545
+ Corresponding Source shall include the Corresponding Source for any
546
+ work covered by version 3 of the GNU General Public License that is
547
+ incorporated pursuant to the following paragraph.
548
+
549
+ Notwithstanding any other provision of this License, you have
550
+ permission to link or combine any covered work with a work licensed
551
+ under version 3 of the GNU General Public License into a single
552
+ combined work, and to convey the resulting work. The terms of this
553
+ License will continue to apply to the part which is the covered work,
554
+ but the work with which it is combined will remain governed by version
555
+ 3 of the GNU General Public License.
556
+
557
+ ### 14. Revised Versions of this License.
558
+
559
+ The Free Software Foundation may publish revised and/or new versions
560
+ of the GNU Affero General Public License from time to time. Such new
561
+ versions will be similar in spirit to the present version, but may
562
+ differ in detail to address new problems or concerns.
563
+
564
+ Each version is given a distinguishing version number. If the Program
565
+ specifies that a certain numbered version of the GNU Affero General
566
+ Public License "or any later version" applies to it, you have the
567
+ option of following the terms and conditions either of that numbered
568
+ version or of any later version published by the Free Software
569
+ Foundation. If the Program does not specify a version number of the
570
+ GNU Affero General Public License, you may choose any version ever
571
+ published by the Free Software Foundation.
572
+
573
+ If the Program specifies that a proxy can decide which future versions
574
+ of the GNU Affero General Public License can be used, that proxy's
575
+ public statement of acceptance of a version permanently authorizes you
576
+ to choose that version for the Program.
577
+
578
+ Later license versions may give you additional or different
579
+ permissions. However, no additional obligations are imposed on any
580
+ author or copyright holder as a result of your choosing to follow a
581
+ later version.
582
+
583
+ ### 15. Disclaimer of Warranty.
584
+
585
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
586
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
587
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
588
+ WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
589
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
590
+ A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
591
+ PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
592
+ DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
593
+ CORRECTION.
594
+
595
+ ### 16. Limitation of Liability.
596
+
597
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
598
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
599
+ CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
600
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
601
+ ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
602
+ NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
603
+ LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
604
+ TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
605
+ PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
606
+
607
+ ### 17. Interpretation of Sections 15 and 16.
608
+
609
+ If the disclaimer of warranty and limitation of liability provided
610
+ above cannot be given local legal effect according to their terms,
611
+ reviewing courts shall apply local law that most closely approximates
612
+ an absolute waiver of all civil liability in connection with the
613
+ Program, unless a warranty or assumption of liability accompanies a
614
+ copy of the Program in return for a fee.
615
+
616
+ END OF TERMS AND CONDITIONS
617
+
618
+ ## How to Apply These Terms to Your New Programs
619
+
620
+ If you develop a new program, and you want it to be of the greatest
621
+ possible use to the public, the best way to achieve this is to make it
622
+ free software which everyone can redistribute and change under these
623
+ terms.
624
+
625
+ To do so, attach the following notices to the program. It is safest to
626
+ attach them to the start of each source file to most effectively state
627
+ the exclusion of warranty; and each file should have at least the
628
+ "copyright" line and a pointer to where the full notice is found.
629
+
630
+ <one line to give the program's name and a brief idea of what it does.>
631
+ Copyright (C) <year> <name of author>
632
+
633
+ This program is free software: you can redistribute it and/or modify
634
+ it under the terms of the GNU Affero General Public License as
635
+ published by the Free Software Foundation, either version 3 of the
636
+ License, or (at your option) any later version.
637
+
638
+ This program is distributed in the hope that it will be useful,
639
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
640
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
641
+ GNU Affero General Public License for more details.
642
+
643
+ You should have received a copy of the GNU Affero General Public License
644
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
645
+
646
+ Also add information on how to contact you by electronic and paper
647
+ mail.
648
+
649
+ If your software can interact with users remotely through a computer
650
+ network, you should also make sure that it provides a way for users to
651
+ get its source. For example, if your program is a web application, its
652
+ interface could display a "Source" link that leads users to an archive
653
+ of the code. There are many ways you could offer source, and different
654
+ solutions will be better for different programs; see section 13 for
655
+ the specific requirements.
656
+
657
+ You should also get your employer (if you work as a programmer) or
658
+ school, if any, to sign a "copyright disclaimer" for the program, if
659
+ necessary. For more information on this, and how to apply and follow
660
+ the GNU AGPL, see <https://www.gnu.org/licenses/>.
Makefile ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Makefile for Jan Electron App - Build, Lint, Test, and Clean
2
+
3
+ REPORT_PORTAL_URL ?= ""
4
+ REPORT_PORTAL_API_KEY ?= ""
5
+ REPORT_PORTAL_PROJECT_NAME ?= ""
6
+ REPORT_PORTAL_LAUNCH_NAME ?= "Jan App"
7
+ REPORT_PORTAL_DESCRIPTION ?= "Jan App report"
8
+
9
+ # Default target, does nothing
10
+ all:
11
+ @echo "Specify a target to run"
12
+
13
+ # Builds the UI kit
14
+ build-joi:
15
+ ifeq ($(OS),Windows_NT)
16
+ cd joi && yarn config set network-timeout 300000 && yarn install && yarn build
17
+ else
18
+ cd joi && yarn install && yarn build
19
+ endif
20
+
21
+ # Installs yarn dependencies and builds core and extensions
22
+ install-and-build: build-joi
23
+ ifeq ($(OS),Windows_NT)
24
+ yarn config set network-timeout 300000
25
+ endif
26
+ yarn global add turbo@1.13.2
27
+ yarn build:core
28
+ yarn build:server
29
+ yarn install
30
+ yarn build:extensions
31
+
32
+ check-file-counts: install-and-build
33
+ ifeq ($(OS),Windows_NT)
34
+ powershell -Command "if ((Get-ChildItem -Path pre-install -Filter *.tgz | Measure-Object | Select-Object -ExpandProperty Count) -ne (Get-ChildItem -Path extensions -Directory | Where-Object Name -like *-extension* | Measure-Object | Select-Object -ExpandProperty Count)) { Write-Host 'Number of .tgz files in pre-install does not match the number of subdirectories in extensions with package.json'; exit 1 } else { Write-Host 'Extension build successful' }"
35
+ else
36
+ @tgz_count=$$(find pre-install -type f -name "*.tgz" | wc -l); dir_count=$$(find extensions -mindepth 1 -maxdepth 1 -type d -exec test -e '{}/package.json' \; -print | wc -l); if [ $$tgz_count -ne $$dir_count ]; then echo "Number of .tgz files in pre-install ($$tgz_count) does not match the number of subdirectories in extension ($$dir_count)"; exit 1; else echo "Extension build successful"; fi
37
+ endif
38
+
39
+ dev: check-file-counts
40
+ yarn dev
41
+
42
+ # Linting
43
+ lint: check-file-counts
44
+ yarn lint
45
+
46
+ update-playwright-config:
47
+ ifeq ($(OS),Windows_NT)
48
+ echo -e "const RPconfig = {\n\
49
+ apiKey: '$(REPORT_PORTAL_API_KEY)',\n\
50
+ endpoint: '$(REPORT_PORTAL_URL)',\n\
51
+ project: '$(REPORT_PORTAL_PROJECT_NAME)',\n\
52
+ launch: '$(REPORT_PORTAL_LAUNCH_NAME)',\n\
53
+ attributes: [\n\
54
+ {\n\
55
+ key: 'key',\n\
56
+ value: 'value',\n\
57
+ },\n\
58
+ {\n\
59
+ value: 'value',\n\
60
+ },\n\
61
+ ],\n\
62
+ description: '$(REPORT_PORTAL_DESCRIPTION)',\n\
63
+ }\n$$(cat electron/playwright.config.ts)" > electron/playwright.config.ts;
64
+ sed -i "s/^ reporter: .*/ reporter: [['@reportportal\/agent-js-playwright', RPconfig]],/" electron/playwright.config.ts
65
+
66
+ else ifeq ($(shell uname -s),Linux)
67
+ echo "const RPconfig = {\n\
68
+ apiKey: '$(REPORT_PORTAL_API_KEY)',\n\
69
+ endpoint: '$(REPORT_PORTAL_URL)',\n\
70
+ project: '$(REPORT_PORTAL_PROJECT_NAME)',\n\
71
+ launch: '$(REPORT_PORTAL_LAUNCH_NAME)',\n\
72
+ attributes: [\n\
73
+ {\n\
74
+ key: 'key',\n\
75
+ value: 'value',\n\
76
+ },\n\
77
+ {\n\
78
+ value: 'value',\n\
79
+ },\n\
80
+ ],\n\
81
+ description: '$(REPORT_PORTAL_DESCRIPTION)',\n\
82
+ }\n$$(cat electron/playwright.config.ts)" > electron/playwright.config.ts;
83
+ sed -i "s/^ reporter: .*/ reporter: [['@reportportal\/agent-js-playwright', RPconfig]],/" electron/playwright.config.ts
84
+ else
85
+ echo "const RPconfig = {\n\
86
+ apiKey: '$(REPORT_PORTAL_API_KEY)',\n\
87
+ endpoint: '$(REPORT_PORTAL_URL)',\n\
88
+ project: '$(REPORT_PORTAL_PROJECT_NAME)',\n\
89
+ launch: '$(REPORT_PORTAL_LAUNCH_NAME)',\n\
90
+ attributes: [\n\
91
+ {\n\
92
+ key: 'key',\n\
93
+ value: 'value',\n\
94
+ },\n\
95
+ {\n\
96
+ value: 'value',\n\
97
+ },\n\
98
+ ],\n\
99
+ description: '$(REPORT_PORTAL_DESCRIPTION)',\n\
100
+ }\n$$(cat electron/playwright.config.ts)" > electron/playwright.config.ts;
101
+ sed -i '' "s|^ reporter: .*| reporter: [['@reportportal\/agent-js-playwright', RPconfig]],|" electron/playwright.config.ts
102
+ endif
103
+
104
+ # Testing
105
+ test: lint
106
+ yarn build:test
107
+ yarn test:unit
108
+ yarn test
109
+
110
+ # Builds and publishes the app
111
+ build-and-publish: check-file-counts
112
+ yarn build:publish
113
+
114
+ # Build
115
+ build: check-file-counts
116
+ yarn build
117
+
118
+ clean:
119
+ ifeq ($(OS),Windows_NT)
120
+ -powershell -Command "Get-ChildItem -Path . -Include node_modules, .next, dist, build, out, .turbo -Recurse -Directory | Remove-Item -Recurse -Force"
121
+ -powershell -Command "Get-ChildItem -Path . -Include package-lock.json -Recurse -File | Remove-Item -Recurse -Force"
122
+ -powershell -Command "Get-ChildItem -Path . -Include yarn.lock -Recurse -File | Remove-Item -Recurse -Force"
123
+ -powershell -Command "Remove-Item -Recurse -Force ./pre-install/*.tgz"
124
+ -powershell -Command "Remove-Item -Recurse -Force ./extensions/*/*.tgz"
125
+ -powershell -Command "Remove-Item -Recurse -Force ./electron/pre-install/*.tgz"
126
+ -powershell -Command "if (Test-Path \"$($env:USERPROFILE)\jan\extensions\") { Remove-Item -Path \"$($env:USERPROFILE)\jan\extensions\" -Recurse -Force }"
127
+ else ifeq ($(shell uname -s),Linux)
128
+ find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
129
+ find . -name ".next" -type d -exec rm -rf '{}' +
130
+ find . -name "dist" -type d -exec rm -rf '{}' +
131
+ find . -name "build" -type d -exec rm -rf '{}' +
132
+ find . -name "out" -type d -exec rm -rf '{}' +
133
+ find . -name ".turbo" -type d -exec rm -rf '{}' +
134
+ find . -name "packake-lock.json" -type f -exec rm -rf '{}' +
135
+ find . -name "yarn.lock" -type f -exec rm -rf '{}' +
136
+ rm -rf ./pre-install/*.tgz
137
+ rm -rf ./extensions/*/*.tgz
138
+ rm -rf ./electron/pre-install/*.tgz
139
+ rm -rf "~/jan/extensions"
140
+ rm -rf "~/.cache/jan*"
141
+ else
142
+ find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
143
+ find . -name ".next" -type d -exec rm -rf '{}' +
144
+ find . -name "dist" -type d -exec rm -rf '{}' +
145
+ find . -name "build" -type d -exec rm -rf '{}' +
146
+ find . -name "out" -type d -exec rm -rf '{}' +
147
+ find . -name ".turbo" -type d -exec rm -rf '{}' +
148
+ find . -name "packake-lock.json" -type f -exec rm -rf '{}' +
149
+ find . -name "yarn.lock" -type f -exec rm -rf '{}' +
150
+ rm -rf ./pre-install/*.tgz
151
+ rm -rf ./extensions/*/*.tgz
152
+ rm -rf ./electron/pre-install/*.tgz
153
+ rm -rf ~/jan/extensions
154
+ rm -rf ~/Library/Caches/jan*
155
+ endif
README.md ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Jan - Turn your computer into an AI computer
2
+
3
+ ![Jan banner](https://github.com/janhq/jan/assets/89722390/35daac7d-b895-487c-a6ac-6663daaad78e)
4
+
5
+ <p align="center">
6
+ <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
7
+ <img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/m/janhq/jan"/>
8
+ <img alt="Github Last Commit" src="https://img.shields.io/github/last-commit/janhq/jan"/>
9
+ <img alt="Github Contributors" src="https://img.shields.io/github/contributors/janhq/jan"/>
10
+ <img alt="GitHub closed issues" src="https://img.shields.io/github/issues-closed/janhq/jan"/>
11
+ <img alt="Discord" src="https://img.shields.io/discord/1107178041848909847?label=discord"/>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://jan.ai/guides">Getting Started</a>
16
+ - <a href="https://jan.ai/docs">Docs</a>
17
+ - <a href="https://github.com/janhq/jan/releases">Changelog</a>
18
+ - <a href="https://github.com/janhq/jan/issues">Bug reports</a>
19
+ - <a href="https://discord.gg/AsJ8krTT3N">Discord</a>
20
+ </p>
21
+
22
+ >[!Warning]
23
+ >**Jan is currently in Development**: Expect breaking changes and bugs!
24
+
25
+ Jan is an open-source ChatGPT alternative that runs 100% offline on your computer.
26
+
27
+ **Jan runs on any hardware.** From PCs to multi-GPU clusters, Jan supports universal architectures:
28
+
29
+ - [x] NVIDIA GPUs (fast)
30
+ - [x] Apple M-series (fast)
31
+ - [x] Apple Intel
32
+ - [x] Linux Debian
33
+ - [x] Windows x64
34
+
35
+ ## Download
36
+
37
+ <table>
38
+ <tr style="text-align:center">
39
+ <td style="text-align:center"><b>Version Type</b></td>
40
+ <td style="text-align:center"><b>Windows</b></td>
41
+ <td colspan="2" style="text-align:center"><b>MacOS</b></td>
42
+ <td colspan="2" style="text-align:center"><b>Linux</b></td>
43
+ </tr>
44
+ <tr style="text-align:center">
45
+ <td style="text-align:center"><b>Stable (Recommended)</b></td>
46
+ <td style="text-align:center">
47
+ <a href='https://app.jan.ai/download/latest/win-x64'>
48
+ <img src='https://github.com/janhq/docs/blob/main/static/img/windows.png' style="height:14px; width: 14px" />
49
+ <b>jan.exe</b>
50
+ </a>
51
+ </td>
52
+ <td style="text-align:center">
53
+ <a href='https://app.jan.ai/download/latest/mac-x64'>
54
+ <img src='https://github.com/janhq/docs/blob/main/static/img/mac.png' style="height:15px; width: 15px" />
55
+ <b>Intel</b>
56
+ </a>
57
+ </td>
58
+ <td style="text-align:center">
59
+ <a href='https://app.jan.ai/download/latest/mac-arm64'>
60
+ <img src='https://github.com/janhq/docs/blob/main/static/img/mac.png' style="height:15px; width: 15px" />
61
+ <b>M1/M2/M3/M4</b>
62
+ </a>
63
+ </td>
64
+ <td style="text-align:center">
65
+ <a href='https://app.jan.ai/download/latest/linux-amd64-deb'>
66
+ <img src='https://github.com/janhq/docs/blob/main/static/img/linux.png' style="height:14px; width: 14px" />
67
+ <b>jan.deb</b>
68
+ </a>
69
+ </td>
70
+ <td style="text-align:center">
71
+ <a href='https://app.jan.ai/download/latest/linux-amd64-appimage'>
72
+ <img src='https://github.com/janhq/docs/blob/main/static/img/linux.png' style="height:14px; width: 14px" />
73
+ <b>jan.AppImage</b>
74
+ </a>
75
+ </td>
76
+ </tr>
77
+ <tr style="text-align:center">
78
+ <td style="text-align:center"><b>Experimental (Nightly Build)</b></td>
79
+ <td style="text-align:center">
80
+ <a href='https://app.jan.ai/download/nightly/win-x64'>
81
+ <img src='https://github.com/janhq/docs/blob/main/static/img/windows.png' style="height:14px; width: 14px" />
82
+ <b>jan.exe</b>
83
+ </a>
84
+ </td>
85
+ <td style="text-align:center">
86
+ <a href='https://app.jan.ai/download/nightly/mac-x64'>
87
+ <img src='https://github.com/janhq/docs/blob/main/static/img/mac.png' style="height:15px; width: 15px" />
88
+ <b>Intel</b>
89
+ </a>
90
+ </td>
91
+ <td style="text-align:center">
92
+ <a href='https://app.jan.ai/download/nightly/mac-arm64'>
93
+ <img src='https://github.com/janhq/docs/blob/main/static/img/mac.png' style="height:15px; width: 15px" />
94
+ <b>M1/M2/M3/M4</b>
95
+ </a>
96
+ </td>
97
+ <td style="text-align:center">
98
+ <a href='https://app.jan.ai/download/nightly/linux-amd64-deb'>
99
+ <img src='https://github.com/janhq/docs/blob/main/static/img/linux.png' style="height:14px; width: 14px" />
100
+ <b>jan.deb</b>
101
+ </a>
102
+ </td>
103
+ <td style="text-align:center">
104
+ <a href='https://app.jan.ai/download/nightly/linux-amd64-appimage'>
105
+ <img src='https://github.com/janhq/docs/blob/main/static/img/linux.png' style="height:14px; width: 14px" />
106
+ <b>jan.AppImage</b>
107
+ </a>
108
+ </td>
109
+ </tr>
110
+ </table>
111
+
112
+ Download the latest version of Jan at https://jan.ai/ or visit the **[GitHub Releases](https://github.com/janhq/jan/releases)** to download any previous release.
113
+
114
+ ## Demo
115
+
116
+ ![Demo](/demo.gif)
117
+
118
+ _Realtime Video: Jan v0.4.3-nightly on a Mac M1, 16GB Sonoma 14_
119
+
120
+ ## Quicklinks
121
+
122
+ #### Jan
123
+
124
+ - [Jan website](https://jan.ai/)
125
+ - [Jan GitHub](https://github.com/janhq/jan)
126
+ - [User Guides](https://jan.ai/guides/)
127
+ - [Developer docs](https://jan.ai/developer/)
128
+ - [API reference](https://jan.ai/api-reference/)
129
+ - [Specs](https://jan.ai/docs/)
130
+
131
+ #### Nitro
132
+
133
+ Nitro is a high-efficiency C++ inference engine for edge computing. It is lightweight and embeddable, and can be used on its own within your own projects.
134
+
135
+ - [Nitro Website](https://nitro.jan.ai)
136
+ - [Nitro GitHub](https://github.com/janhq/nitro)
137
+ - [Documentation](https://nitro.jan.ai/docs)
138
+ - [API Reference](https://nitro.jan.ai/api-reference)
139
+
140
+ ## Troubleshooting
141
+
142
+ As Jan is in development mode, you might get stuck on a broken build.
143
+
144
+ To reset your installation:
145
+
146
+ 1. Use the following commands to remove any dangling backend processes:
147
+
148
+ ```sh
149
+ ps aux | grep nitro
150
+ ```
151
+
152
+ Look for processes like "nitro" and "nitro_arm_64," and kill them one by one with:
153
+
154
+ ```sh
155
+ kill -9 <PID>
156
+ ```
157
+
158
+ 2. **Remove Jan from your Applications folder and Cache folder**
159
+
160
+ ```bash
161
+ make clean
162
+ ```
163
+
164
+ This will remove all build artifacts and cached files:
165
+
166
+ - Delete Jan extension from your `~/jan/extensions` folder
167
+ - Delete all `node_modules` in current folder
168
+ - Clear Application cache in `~/Library/Caches/jan`
169
+
170
+ ## Requirements for running Jan
171
+
172
+ - MacOS: 13 or higher
173
+ - Windows:
174
+ - Windows 10 or higher
175
+ - To enable GPU support:
176
+ - Nvidia GPU with CUDA Toolkit 11.7 or higher
177
+ - Nvidia driver 470.63.01 or higher
178
+ - Linux:
179
+ - glibc 2.27 or higher (check with `ldd --version`)
180
+ - gcc 11, g++ 11, cpp 11 or higher, refer to this [link](https://jan.ai/guides/troubleshooting/gpu-not-used/#specific-requirements-for-linux) for more information
181
+ - To enable GPU support:
182
+ - Nvidia GPU with CUDA Toolkit 11.7 or higher
183
+ - Nvidia driver 470.63.01 or higher
184
+
185
+ ## Contributing
186
+
187
+ Contributions are welcome! Please read the [CONTRIBUTING.md](CONTRIBUTING.md) file
188
+
189
+ ### Pre-requisites
190
+
191
+ - node >= 20.0.0
192
+ - yarn >= 1.22.0
193
+ - make >= 3.81
194
+
195
+ ### Instructions
196
+
197
+ 1. **Clone the repository and prepare:**
198
+
199
+ ```bash
200
+ git clone https://github.com/janhq/jan
201
+ cd jan
202
+ git checkout -b DESIRED_BRANCH
203
+ ```
204
+
205
+ 2. **Run development and use Jan Desktop**
206
+
207
+ ```bash
208
+ make dev
209
+ ```
210
+
211
+ This will start the development server and open the desktop app.
212
+
213
+ 3. (Optional) **Run the API server without frontend**
214
+
215
+ ```bash
216
+ yarn dev:server
217
+ ```
218
+
219
+ ### For production build
220
+
221
+ ```bash
222
+ # Do steps 1 and 2 in the previous section
223
+ # Build the app
224
+ make build
225
+ ```
226
+
227
+ This will build the app MacOS m1/m2 for production (with code signing already done) and put the result in `dist` folder.
228
+
229
+ ### Docker mode
230
+
231
+ - Supported OS: Linux, WSL2 Docker
232
+ - Pre-requisites:
233
+
234
+ - Docker Engine and Docker Compose are required to run Jan in Docker mode. Follow the [instructions](https://docs.docker.com/engine/install/ubuntu/) below to get started with Docker Engine on Ubuntu.
235
+
236
+ ```bash
237
+ curl -fsSL https://get.docker.com -o get-docker.sh
238
+ sudo sh ./get-docker.sh --dry-run
239
+ ```
240
+
241
+ - If you intend to run Jan in GPU mode, you need to install `nvidia-driver` and `nvidia-docker2`. Follow the instruction [here](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) for installation.
242
+
243
+ - Run Jan in Docker mode
244
+ > User can choose between `docker-compose.yml` with latest prebuilt docker image or `docker-compose-dev.yml` with local docker build
245
+
246
+ | Docker compose Profile | Description |
247
+ | ---------------------- | -------------------------------------------- |
248
+ | `cpu-fs` | Run Jan in CPU mode with default file system |
249
+ | `cpu-s3fs` | Run Jan in CPU mode with S3 file system |
250
+ | `gpu-fs` | Run Jan in GPU mode with default file system |
251
+ | `gpu-s3fs` | Run Jan in GPU mode with S3 file system |
252
+
253
+ | Environment Variable | Description |
254
+ | ----------------------- | ------------------------------------------------------------------------------------------------------- |
255
+ | `S3_BUCKET_NAME` | S3 bucket name - leave blank for default file system |
256
+ | `AWS_ACCESS_KEY_ID` | AWS access key ID - leave blank for default file system |
257
+ | `AWS_SECRET_ACCESS_KEY` | AWS secret access key - leave blank for default file system |
258
+ | `AWS_ENDPOINT` | AWS endpoint URL - leave blank for default file system |
259
+ | `AWS_REGION` | AWS region - leave blank for default file system |
260
+ | `API_BASE_URL` | Jan Server URL, please modify it as your public ip address or domain name default http://localhost:1377 |
261
+
262
+ - **Option 1**: Run Jan in CPU mode
263
+
264
+ ```bash
265
+ # cpu mode with default file system
266
+ docker compose --profile cpu-fs up -d
267
+
268
+ # cpu mode with S3 file system
269
+ docker compose --profile cpu-s3fs up -d
270
+ ```
271
+
272
+ - **Option 2**: Run Jan in GPU mode
273
+
274
+ - **Step 1**: Check CUDA compatibility with your NVIDIA driver by running `nvidia-smi` and check the CUDA version in the output
275
+
276
+ ```bash
277
+ nvidia-smi
278
+
279
+ # Output
280
+ +---------------------------------------------------------------------------------------+
281
+ | NVIDIA-SMI 531.18 Driver Version: 531.18 CUDA Version: 12.1 |
282
+ |-----------------------------------------+----------------------+----------------------+
283
+ | GPU Name TCC/WDDM | Bus-Id Disp.A | Volatile Uncorr. ECC |
284
+ | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
285
+ | | | MIG M. |
286
+ |=========================================+======================+======================|
287
+ | 0 NVIDIA GeForce RTX 4070 Ti WDDM | 00000000:01:00.0 On | N/A |
288
+ | 0% 44C P8 16W / 285W| 1481MiB / 12282MiB | 2% Default |
289
+ | | | N/A |
290
+ +-----------------------------------------+----------------------+----------------------+
291
+ | 1 NVIDIA GeForce GTX 1660 Ti WDDM | 00000000:02:00.0 Off | N/A |
292
+ | 0% 49C P8 14W / 120W| 0MiB / 6144MiB | 0% Default |
293
+ | | | N/A |
294
+ +-----------------------------------------+----------------------+----------------------+
295
+ | 2 NVIDIA GeForce GTX 1660 Ti WDDM | 00000000:05:00.0 Off | N/A |
296
+ | 29% 38C P8 11W / 120W| 0MiB / 6144MiB | 0% Default |
297
+ | | | N/A |
298
+ +-----------------------------------------+----------------------+----------------------+
299
+
300
+ +---------------------------------------------------------------------------------------+
301
+ | Processes: |
302
+ | GPU GI CI PID Type Process name GPU Memory |
303
+ | ID ID Usage |
304
+ |=======================================================================================|
305
+ ```
306
+
307
+ - **Step 2**: Visit [NVIDIA NGC Catalog ](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/cuda/tags) and find the smallest minor version of image tag that matches your CUDA version (e.g., 12.1 -> 12.1.0)
308
+
309
+ - **Step 3**: Update the `Dockerfile.gpu` line number 5 with the latest minor version of the image tag from step 2 (e.g. change `FROM nvidia/cuda:12.2.0-runtime-ubuntu22.04 AS base` to `FROM nvidia/cuda:12.1.0-runtime-ubuntu22.04 AS base`)
310
+
311
+ - **Step 4**: Run command to start Jan in GPU mode
312
+
313
+ ```bash
314
+ # GPU mode with default file system
315
+ docker compose --profile gpu-fs up -d
316
+
317
+ # GPU mode with S3 file system
318
+ docker compose --profile gpu-s3fs up -d
319
+ ```
320
+
321
+ This will start the web server and you can access Jan at `http://localhost:3000`.
322
+
323
+ > Note: RAG feature is not supported in Docker mode with s3fs yet.
324
+
325
+ ## Acknowledgements
326
+
327
+ Jan builds on top of other open-source projects:
328
+
329
+ - [llama.cpp](https://github.com/ggerganov/llama.cpp)
330
+ - [LangChain](https://github.com/langchain-ai)
331
+ - [TensorRT](https://github.com/NVIDIA/TensorRT)
332
+ - [TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM)
333
+
334
+ ## Contact
335
+
336
+ - Bugs & requests: file a GitHub ticket
337
+ - For discussion: join our Discord [here](https://discord.gg/FTk2MvZwJH)
338
+ - For business inquiries: email hello@jan.ai
339
+ - For jobs: please email hr@jan.ai
340
+
341
+ ## Trust & Safety
342
+
343
+ Beware of scams.
344
+
345
+ - We will never ask you for personal info
346
+ - We are a free product; there's no paid version
347
+ - We don't have a token or ICO
348
+ - We are not actively fundraising or seeking donations
349
+
350
+ ## License
351
+
352
+ Jan is free and open source, under the AGPLv3 license.
charts/server/Chart.lock ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ dependencies:
2
+ - name: common
3
+ repository: oci://ghcr.io/janhq/charts
4
+ version: 0.1.2
5
+ digest: sha256:35e98bde174130787755b0f8ea2359b7b6790d965a7157c2f7cabf1bc8c04471
6
+ generated: "2024-02-20T16:20:37.6530108+07:00"
charts/server/Chart.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ apiVersion: v2
2
+ name: jan-server
3
+ description: A Helm chart for Kubernetes
4
+ type: application
5
+ version: 0.1.0
6
+ appVersion: '1.0.0'
7
+ dependencies:
8
+ - name: common
9
+ version: 0.1.2 # common-chart-version
10
+ repository: oci://ghcr.io/janhq/charts
charts/server/charts/common-0.1.2.tgz ADDED
Binary file (7.15 kB). View file
 
charts/server/config.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "image-list": "server=ghcr.io/janhq/jan-server",
3
+ "platforms": "linux/amd64"
4
+ }
charts/server/values.yaml ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ common:
2
+ imageTag: v0.4.6-cpu
3
+ # DO NOT CHANGE THE LINE ABOVE. MAKE ALL CHANGES BELOW
4
+
5
+ # Global pvc for all workload
6
+ pvc:
7
+ enabled: false
8
+ name: 'janroot'
9
+ accessModes: 'ReadWriteOnce'
10
+ storageClassName: ''
11
+ capacity: '50Gi'
12
+
13
+ # Global image pull secret
14
+ imagePullSecrets: []
15
+
16
+ externalSecret:
17
+ create: false
18
+ name: ''
19
+ annotations: {}
20
+
21
+ nameOverride: 'jan-server'
22
+ fullnameOverride: 'jan-server'
23
+
24
+ serviceAccount:
25
+ create: true
26
+ annotations: {}
27
+ name: 'jan-server-service-account'
28
+
29
+ podDisruptionBudget:
30
+ create: false
31
+ minAvailable: 1
32
+
33
+ workloads:
34
+ - name: server
35
+ image:
36
+ repository: ghcr.io/janhq/jan-server
37
+ pullPolicy: Always
38
+
39
+ command: ['/bin/sh', '-c']
40
+ args: ['cd server && node build/main.js']
41
+
42
+ replicaCount: 1
43
+ ports:
44
+ containerPort: 1337
45
+
46
+ strategy:
47
+ canary:
48
+ steps:
49
+ - setWeight: 50
50
+ - pause: { duration: 1m }
51
+
52
+ ingress:
53
+ enabled: true
54
+ className: 'nginx'
55
+ annotations:
56
+ nginx.ingress.kubernetes.io/proxy-body-size: '100m'
57
+ nginx.ingress.kubernetes.io/proxy-read-timeout: '1800'
58
+ nginx.ingress.kubernetes.io/proxy-send-timeout: '1800'
59
+ # cert-manager.io/cluster-issuer: 'jan-ai-dns01-cluster-issuer'
60
+ # nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'
61
+ nginx.ingress.kubernetes.io/backend-protocol: HTTP
62
+ hosts:
63
+ - host: server.local
64
+ paths:
65
+ - path: /
66
+ pathType: Prefix
67
+ tls:
68
+ []
69
+ # - hosts:
70
+ # - server-dev.jan.ai
71
+ # secretName: jan-server-prod-tls-v2
72
+
73
+ instrumentation:
74
+ enabled: false
75
+ podAnnotations: {}
76
+
77
+ podSecurityContext: {}
78
+
79
+ securityContext: {}
80
+
81
+ service:
82
+ externalLabel: {}
83
+ type: ClusterIP
84
+ port: 1337
85
+ targetPort: 1337
86
+
87
+ # If you want to use GPU, please uncomment the following lines and change imageTag to the one with GPU support
88
+ resources:
89
+ # limits:
90
+ # nvidia.com/gpu: 1
91
+ requests:
92
+ cpu: 2000m
93
+ memory: 8192M
94
+
95
+ # If you want to use pv, please uncomment the following lines and enable pvc.enabled
96
+ volumes:
97
+ []
98
+ # - name: janroot
99
+ # persistentVolumeClaim:
100
+ # claimName: janroot
101
+
102
+ volumeMounts:
103
+ []
104
+ # - name: janroot
105
+ # mountPath: /app/server/build/jan
106
+
107
+ # AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_BUCKET_NAME, AWS_ENDPOINT, AWS_REGION should mount as a secret env instead of plain text here
108
+ # Change API_BASE_URL to your server's public domain
109
+ env:
110
+ - name: API_BASE_URL
111
+ value: 'http://server.local'
112
+
113
+ lifecycle: {}
114
+ autoscaling:
115
+ enabled: false
116
+ minReplicas: 2
117
+ maxReplicas: 3
118
+ targetCPUUtilizationPercentage: 95
119
+ targetMemoryUtilizationPercentage: 95
120
+
121
+ kedaScaling:
122
+ enabled: false # ignore if autoscaling.enable = true
123
+ cooldownPeriod: 30
124
+ pollingInterval: 2
125
+ minReplicas: 1
126
+ maxReplicas: 5
127
+ metricName: celery_queue_length
128
+ query: celery_queue_length{queue_name="myqueue"} # change queue_name here
129
+ serverAddress: http://prometheus-prod-kube-prome-prometheus.monitoring.svc:9090
130
+ threshold: '3'
131
+
132
+ nodeSelector: {}
133
+
134
+ tolerations: []
135
+
136
+ podSecurityGroup:
137
+ enabled: false
138
+ securitygroupid: []
139
+
140
+ # Reloader Option
141
+ reloader: 'false'
142
+ vpa:
143
+ enabled: false
144
+
145
+ - name: web
146
+ image:
147
+ repository: ghcr.io/janhq/jan-server
148
+ pullPolicy: Always
149
+
150
+ command: ['/bin/sh', '-c']
151
+ args:
152
+ [
153
+ 'export NODE_ENV=production && yarn workspace @janhq/web build && cd web && npx serve out',
154
+ ]
155
+
156
+ replicaCount: 1
157
+ ports:
158
+ containerPort: 3000
159
+
160
+ strategy:
161
+ canary:
162
+ steps:
163
+ - setWeight: 50
164
+ - pause: { duration: 1m }
165
+
166
+ ingress:
167
+ enabled: true
168
+ className: 'nginx'
169
+ annotations:
170
+ nginx.ingress.kubernetes.io/proxy-body-size: '100m'
171
+ nginx.ingress.kubernetes.io/proxy-read-timeout: '1800'
172
+ nginx.ingress.kubernetes.io/proxy-send-timeout: '1800'
173
+ # cert-manager.io/cluster-issuer: 'jan-ai-dns01-cluster-issuer'
174
+ # nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'
175
+ nginx.ingress.kubernetes.io/backend-protocol: HTTP
176
+ hosts:
177
+ - host: web.local
178
+ paths:
179
+ - path: /
180
+ pathType: Prefix
181
+ tls:
182
+ []
183
+ # - hosts:
184
+ # - server-dev.jan.ai
185
+ # secretName: jan-server-prod-tls-v2
186
+
187
+ instrumentation:
188
+ enabled: false
189
+ podAnnotations: {}
190
+
191
+ podSecurityContext: {}
192
+
193
+ securityContext: {}
194
+
195
+ service:
196
+ externalLabel: {}
197
+ type: ClusterIP
198
+ port: 3000
199
+ targetPort: 3000
200
+
201
+ resources:
202
+ limits:
203
+ cpu: 1000m
204
+ memory: 2048M
205
+ requests:
206
+ cpu: 50m
207
+ memory: 500M
208
+
209
+ volumes:
210
+ []
211
+ # - name: janroot
212
+ # persistentVolumeClaim:
213
+ # claimName: janroot
214
+
215
+ volumeMounts:
216
+ []
217
+ # - name: janroot
218
+ # mountPath: /app/server/build/jan
219
+
220
+ # AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_BUCKET_NAME, AWS_ENDPOINT, AWS_REGION should mount as a secret env instead of plain text here
221
+ # Change API_BASE_URL to your server's public domain
222
+ env:
223
+ - name: API_BASE_URL
224
+ value: 'http://server.local'
225
+
226
+ lifecycle: {}
227
+ autoscaling:
228
+ enabled: true
229
+ minReplicas: 1
230
+ maxReplicas: 3
231
+ targetCPUUtilizationPercentage: 95
232
+ targetMemoryUtilizationPercentage: 95
233
+
234
+ kedaScaling:
235
+ enabled: false # ignore if autoscaling.enable = true
236
+ cooldownPeriod: 30
237
+ pollingInterval: 2
238
+ minReplicas: 1
239
+ maxReplicas: 5
240
+ metricName: celery_queue_length
241
+ query: celery_queue_length{queue_name="myqueue"} # change queue_name here
242
+ serverAddress: http://prometheus-prod-kube-prome-prometheus.monitoring.svc:9090
243
+ threshold: '3'
244
+
245
+ nodeSelector: {}
246
+
247
+ tolerations: []
248
+
249
+ podSecurityGroup:
250
+ enabled: false
251
+ securitygroupid: []
252
+
253
+ # Reloader Option
254
+ reloader: 'false'
255
+ vpa:
256
+ enabled: false
core/.editorconfig ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ end_of_line = lf
6
+ charset = utf-8
7
+ trim_trailing_whitespace = true
8
+ insert_final_newline = true
9
+ max_line_length = 100
10
+ indent_size = 2
11
+
12
+ [*.md]
13
+ trim_trailing_whitespace = false
core/.gitignore ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ node_modules
2
+ coverage
3
+ .nyc_output
4
+ .DS_Store
5
+ *.log
6
+ .vscode
7
+ .idea
8
+ dist
9
+ docs
core/README.md ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## @janhq/core
2
+
3
+ > This module includes functions for communicating with core APIs, registering app extensions, and exporting type definitions.
4
+
5
+ ## Usage
6
+
7
+ ### Import the package
8
+
9
+ ```js
10
+ // Web / extension runtime
11
+ import * as core from "@janhq/core";
12
+
13
+ // Node runtime
14
+ import * as node from "@janhq/core/node";
15
+ ```
16
+
17
+ ## Build an Extension
18
+
19
+ 1. Download an extension template, for example, [https://github.com/janhq/extension-template](https://github.com/janhq/extension-template).
20
+
21
+ 2. Update the source code:
22
+ 1. Open `index.ts` in your code editor.
23
+ 2. Rename the extension class from `SampleExtension` to your preferred extension name.
24
+ 3. Import modules from the core package.
25
+ ```ts
26
+ import * as core from "@janhq/core";
27
+ ```
28
+ 4. In the `onLoad()` method, add your code:
29
+ ```ts
30
+ // Example of listening to app events and providing customized inference logic:
31
+ import * as core from "@janhq/core";
32
+
33
+ export default class MyExtension extends BaseExtension {
34
+ // On extension load
35
+ onLoad() {
36
+ core.events.on(MessageEvent.OnMessageSent, (data) => MyExtension.inference(data, this));
37
+ }
38
+
39
+ // Customized inference logic
40
+ private static inference(incomingMessage: MessageRequestData) {
41
+
42
+ // Prepare customized message content
43
+ const content: ThreadContent = {
44
+ type: ContentType.Text,
45
+ text: {
46
+ value: "I'm Jan Assistant!",
47
+ annotations: [],
48
+ },
49
+ };
50
+
51
+ // Modify message and send out
52
+ const outGoingMessage: ThreadMessage = {
53
+ ...incomingMessage,
54
+ content
55
+ };
56
+ }
57
+ }
58
+ ```
59
+ 3. Build the extension:
60
+ 1. Navigate to the extension directory.
61
+ 2. Install dependencies.
62
+ ```bash
63
+ yarn install
64
+ ```
65
+ 3. Compile the source code. The following command keeps running in the terminal and rebuilds the extension when you modify the source code.
66
+ ```bash
67
+ yarn build
68
+ ```
69
+ 4. Select the generated .tgz from Jan > Settings > Extension > Manual Installation.
core/jest.config.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ preset: 'ts-jest',
3
+ testEnvironment: 'node',
4
+ moduleNameMapper: {
5
+ '@/(.*)': '<rootDir>/src/$1',
6
+ },
7
+ }
core/package.json ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "@janhq/core",
3
+ "version": "0.1.10",
4
+ "description": "Jan app core lib",
5
+ "keywords": [
6
+ "jan",
7
+ "core"
8
+ ],
9
+ "homepage": "https://jan.ai",
10
+ "license": "AGPL-3.0",
11
+ "main": "dist/core.es5.js",
12
+ "module": "dist/core.cjs.js",
13
+ "typings": "dist/types/index.d.ts",
14
+ "files": [
15
+ "dist",
16
+ "types"
17
+ ],
18
+ "author": "Jan <service@jan.ai>",
19
+ "exports": {
20
+ ".": "./dist/core.es5.js",
21
+ "./node": "./dist/node/index.cjs.js"
22
+ },
23
+ "typesVersions": {
24
+ "*": {
25
+ ".": [
26
+ "./dist/core.es5.js.map",
27
+ "./dist/types/index.d.ts"
28
+ ],
29
+ "node": [
30
+ "./dist/node/index.cjs.js.map",
31
+ "./dist/types/node/index.d.ts"
32
+ ]
33
+ }
34
+ },
35
+ "scripts": {
36
+ "lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'",
37
+ "test": "jest",
38
+ "prebuild": "rimraf dist",
39
+ "build": "tsc --module commonjs && rollup -c rollup.config.ts",
40
+ "start": "rollup -c rollup.config.ts -w"
41
+ },
42
+ "devDependencies": {
43
+ "@rollup/plugin-replace": "^5.0.5",
44
+ "@types/jest": "^29.5.12",
45
+ "@types/node": "^20.11.4",
46
+ "eslint": "8.57.0",
47
+ "eslint-plugin-jest": "^27.9.0",
48
+ "jest": "^29.7.0",
49
+ "rimraf": "^3.0.2",
50
+ "rollup": "^2.38.5",
51
+ "rollup-plugin-commonjs": "^9.1.8",
52
+ "rollup-plugin-json": "^3.1.0",
53
+ "rollup-plugin-node-resolve": "^5.2.0",
54
+ "rollup-plugin-sourcemaps": "^0.6.3",
55
+ "rollup-plugin-typescript2": "^0.36.0",
56
+ "ts-jest": "^29.1.2",
57
+ "tslib": "^2.6.2",
58
+ "typescript": "^5.3.3"
59
+ },
60
+ "dependencies": {
61
+ "rxjs": "^7.8.1",
62
+ "ulidx": "^2.3.0"
63
+ }
64
+ }
core/rollup.config.ts ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import resolve from 'rollup-plugin-node-resolve'
2
+ import commonjs from 'rollup-plugin-commonjs'
3
+ import sourceMaps from 'rollup-plugin-sourcemaps'
4
+ import typescript from 'rollup-plugin-typescript2'
5
+ import json from 'rollup-plugin-json'
6
+ import replace from '@rollup/plugin-replace'
7
+
8
+ const pkg = require('./package.json')
9
+
10
+ export default [
11
+ {
12
+ input: `src/index.ts`,
13
+ output: [
14
+ // { file: pkg.main, name: libraryName, format: 'umd', sourcemap: true },
15
+ { file: pkg.main, format: 'es', sourcemap: true },
16
+ ],
17
+ // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
18
+ external: ['path'],
19
+ watch: {
20
+ include: 'src/**',
21
+ },
22
+ plugins: [
23
+ // Allow json resolution
24
+ json(),
25
+ // Compile TypeScript files
26
+ typescript({ useTsconfigDeclarationDir: true }),
27
+ // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
28
+ commonjs(),
29
+ // Allow node_modules resolution, so you can use 'external' to control
30
+ // which external modules to include in the bundle
31
+ // https://github.com/rollup/rollup-plugin-node-resolve#usage
32
+ replace({
33
+ 'preventAssignment': true,
34
+ 'node:crypto': 'crypto',
35
+ 'delimiters': ['"', '"'],
36
+ }),
37
+ resolve({
38
+ browser: true,
39
+ }),
40
+
41
+ // Resolve source maps to the original source
42
+ sourceMaps(),
43
+ ],
44
+ },
45
+ {
46
+ input: `src/node/index.ts`,
47
+ output: [{ file: 'dist/node/index.cjs.js', format: 'cjs', sourcemap: true }],
48
+ // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
49
+ external: [
50
+ 'fs/promises',
51
+ 'path',
52
+ 'pacote',
53
+ '@types/pacote',
54
+ '@npmcli/arborist',
55
+ 'ulidx',
56
+ 'node-fetch',
57
+ 'fs',
58
+ 'request',
59
+ 'crypto',
60
+ 'url',
61
+ 'http',
62
+ 'os',
63
+ 'util',
64
+ 'child_process',
65
+ ],
66
+ watch: {
67
+ include: 'src/node/**',
68
+ },
69
+ plugins: [
70
+ // Allow json resolution
71
+ json(),
72
+ // Compile TypeScript files
73
+ typescript({ useTsconfigDeclarationDir: true }),
74
+ // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
75
+ commonjs(),
76
+ // Allow node_modules resolution, so you can use 'external' to control
77
+ // which external modules to include in the bundle
78
+ // https://github.com/rollup/rollup-plugin-node-resolve#usage
79
+ resolve(),
80
+
81
+ // Resolve source maps to the original source
82
+ sourceMaps(),
83
+ ],
84
+ },
85
+ ]
core/src/@global/index.d.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ export {}
2
+
3
+ declare global {
4
+ namespace NodeJS {
5
+ interface Global {
6
+ core: any
7
+ }
8
+ }
9
+ var core: any | undefined
10
+ }
core/src/browser/core.ts ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { DownloadRequest, FileStat, NetworkConfig, SystemInformation } from '../types'
2
+
3
+ /**
4
+ * Execute a extension module function in main process
5
+ *
6
+ * @param extension extension name to import
7
+ * @param method function name to execute
8
+ * @param args arguments to pass to the function
9
+ * @returns Promise<any>
10
+ *
11
+ */
12
+ const executeOnMain: (extension: string, method: string, ...args: any[]) => Promise<any> = (
13
+ extension,
14
+ method,
15
+ ...args
16
+ ) => globalThis.core?.api?.invokeExtensionFunc(extension, method, ...args)
17
+
18
+ /**
19
+ * Downloads a file from a URL and saves it to the local file system.
20
+ *
21
+ * @param {DownloadRequest} downloadRequest - The request to download the file.
22
+ * @param {NetworkConfig} network - Optional object to specify proxy/whether to ignore SSL certificates.
23
+ *
24
+ * @returns {Promise<any>} A promise that resolves when the file is downloaded.
25
+ */
26
+ const downloadFile: (downloadRequest: DownloadRequest, network?: NetworkConfig) => Promise<any> = (
27
+ downloadRequest,
28
+ network
29
+ ) => globalThis.core?.api?.downloadFile(downloadRequest, network)
30
+
31
+ /**
32
+ * Get unit in bytes for a remote file.
33
+ *
34
+ * @param url - The url of the file.
35
+ * @returns {Promise<number>} - A promise that resolves with the file size.
36
+ */
37
+ const getFileSize: (url: string) => Promise<number> = (url: string) =>
38
+ globalThis.core.api?.getFileSize(url)
39
+
40
+ /**
41
+ * Aborts the download of a specific file.
42
+ * @param {string} fileName - The name of the file whose download is to be aborted.
43
+ * @returns {Promise<any>} A promise that resolves when the download has been aborted.
44
+ */
45
+ const abortDownload: (fileName: string) => Promise<any> = (fileName) =>
46
+ globalThis.core.api?.abortDownload(fileName)
47
+
48
+ /**
49
+ * Gets Jan's data folder path.
50
+ *
51
+ * @returns {Promise<string>} A Promise that resolves with Jan's data folder path.
52
+ */
53
+ const getJanDataFolderPath = (): Promise<string> => globalThis.core.api?.getJanDataFolderPath()
54
+
55
+ /**
56
+ * Opens the file explorer at a specific path.
57
+ * @param {string} path - The path to open in the file explorer.
58
+ * @returns {Promise<any>} A promise that resolves when the file explorer is opened.
59
+ */
60
+ const openFileExplorer: (path: string) => Promise<any> = (path) =>
61
+ globalThis.core.api?.openFileExplorer(path)
62
+
63
+ /**
64
+ * Joins multiple paths together.
65
+ * @param paths - The paths to join.
66
+ * @returns {Promise<string>} A promise that resolves with the joined path.
67
+ */
68
+ const joinPath: (paths: string[]) => Promise<string> = (paths) =>
69
+ globalThis.core.api?.joinPath(paths)
70
+
71
+ /**
72
+ * Retrieve the basename from an url.
73
+ * @param path - The path to retrieve.
74
+ * @returns {Promise<string>} A promise that resolves with the basename.
75
+ */
76
+ const baseName: (paths: string) => Promise<string> = (path) => globalThis.core.api?.baseName(path)
77
+
78
+ /**
79
+ * Opens an external URL in the default web browser.
80
+ *
81
+ * @param {string} url - The URL to open.
82
+ * @returns {Promise<any>} - A promise that resolves when the URL has been successfully opened.
83
+ */
84
+ const openExternalUrl: (url: string) => Promise<any> = (url) =>
85
+ globalThis.core.api?.openExternalUrl(url)
86
+
87
+ /**
88
+ * Gets the resource path of the application.
89
+ *
90
+ * @returns {Promise<string>} - A promise that resolves with the resource path.
91
+ */
92
+ const getResourcePath: () => Promise<string> = () => globalThis.core.api?.getResourcePath()
93
+
94
+ /**
95
+ * Gets the user's home path.
96
+ * @returns return user's home path
97
+ */
98
+ const getUserHomePath = (): Promise<string> => globalThis.core.api?.getUserHomePath()
99
+
100
+ /**
101
+ * Log to file from browser processes.
102
+ *
103
+ * @param message - Message to log.
104
+ */
105
+ const log: (message: string, fileName?: string) => void = (message, fileName) =>
106
+ globalThis.core.api?.log(message, fileName)
107
+
108
+ /**
109
+ * Check whether the path is a subdirectory of another path.
110
+ *
111
+ * @param from - The path to check.
112
+ * @param to - The path to check against.
113
+ *
114
+ * @returns {Promise<boolean>} - A promise that resolves with a boolean indicating whether the path is a subdirectory.
115
+ */
116
+ const isSubdirectory: (from: string, to: string) => Promise<boolean> = (from: string, to: string) =>
117
+ globalThis.core.api?.isSubdirectory(from, to)
118
+
119
+ /**
120
+ * Get system information
121
+ * @returns {Promise<any>} - A promise that resolves with the system information.
122
+ */
123
+ const systemInformation: () => Promise<SystemInformation> = () =>
124
+ globalThis.core.api?.systemInformation()
125
+
126
+ /**
127
+ * Show toast message from browser processes.
128
+ * @param title
129
+ * @param message
130
+ * @returns
131
+ */
132
+ const showToast: (title: string, message: string) => void = (title, message) =>
133
+ globalThis.core.api?.showToast(title, message)
134
+
135
+ /**
136
+ * Register extension point function type definition
137
+ */
138
+ export type RegisterExtensionPoint = (
139
+ extensionName: string,
140
+ extensionId: string,
141
+ method: Function,
142
+ priority?: number
143
+ ) => void
144
+
145
+ /**
146
+ * Functions exports
147
+ */
148
+ export {
149
+ executeOnMain,
150
+ downloadFile,
151
+ abortDownload,
152
+ getJanDataFolderPath,
153
+ openFileExplorer,
154
+ getResourcePath,
155
+ joinPath,
156
+ openExternalUrl,
157
+ baseName,
158
+ log,
159
+ isSubdirectory,
160
+ getUserHomePath,
161
+ systemInformation,
162
+ showToast,
163
+ getFileSize,
164
+ FileStat,
165
+ }
core/src/browser/events.ts ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Adds an observer for an event.
3
+ *
4
+ * @param eventName The name of the event to observe.
5
+ * @param handler The handler function to call when the event is observed.
6
+ */
7
+ const on: (eventName: string, handler: Function) => void = (eventName, handler) => {
8
+ globalThis.core?.events?.on(eventName, handler)
9
+ }
10
+
11
+ /**
12
+ * Removes an observer for an event.
13
+ *
14
+ * @param eventName The name of the event to stop observing.
15
+ * @param handler The handler function to call when the event is observed.
16
+ */
17
+ const off: (eventName: string, handler: Function) => void = (eventName, handler) => {
18
+ globalThis.core?.events?.off(eventName, handler)
19
+ }
20
+
21
+ /**
22
+ * Emits an event.
23
+ *
24
+ * @param eventName The name of the event to emit.
25
+ * @param object The object to pass to the event callback.
26
+ */
27
+ const emit: (eventName: string, object: any) => void = (eventName, object) => {
28
+ globalThis.core?.events?.emit(eventName, object)
29
+ }
30
+
31
+ export const events = {
32
+ on,
33
+ off,
34
+ emit,
35
+ }
core/src/browser/extension.ts ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { SettingComponentProps } from '../types'
2
+ import { getJanDataFolderPath, joinPath } from './core'
3
+ import { fs } from './fs'
4
+
5
+ export enum ExtensionTypeEnum {
6
+ Assistant = 'assistant',
7
+ Conversational = 'conversational',
8
+ Inference = 'inference',
9
+ Model = 'model',
10
+ SystemMonitoring = 'systemMonitoring',
11
+ HuggingFace = 'huggingFace',
12
+ }
13
+
14
+ export interface ExtensionType {
15
+ type(): ExtensionTypeEnum | undefined
16
+ }
17
+
18
+ export interface Compatibility {
19
+ platform: string[]
20
+ version: string
21
+ }
22
+
23
+ const ALL_INSTALLATION_STATE = [
24
+ 'NotRequired', // not required.
25
+ 'Installed', // require and installed. Good to go.
26
+ 'NotInstalled', // require to be installed.
27
+ 'Corrupted', // require but corrupted. Need to redownload.
28
+ 'NotCompatible', // require but not compatible.
29
+ ] as const
30
+
31
+ export type InstallationStateTuple = typeof ALL_INSTALLATION_STATE
32
+ export type InstallationState = InstallationStateTuple[number]
33
+
34
+ /**
35
+ * Represents a base extension.
36
+ * This class should be extended by any class that represents an extension.
37
+ */
38
+ export abstract class BaseExtension implements ExtensionType {
39
+ protected settingFolderName = 'settings'
40
+ protected settingFileName = 'settings.json'
41
+
42
+ /** @type {string} Name of the extension. */
43
+ name: string
44
+
45
+ /** @type {string} Product Name of the extension. */
46
+ productName?: string
47
+
48
+ /** @type {string} The URL of the extension to load. */
49
+ url: string
50
+
51
+ /** @type {boolean} Whether the extension is activated or not. */
52
+ active
53
+
54
+ /** @type {string} Extension's description. */
55
+ description
56
+
57
+ /** @type {string} Extension's version. */
58
+ version
59
+
60
+ constructor(
61
+ url: string,
62
+ name: string,
63
+ productName?: string,
64
+ active?: boolean,
65
+ description?: string,
66
+ version?: string
67
+ ) {
68
+ this.name = name
69
+ this.productName = productName
70
+ this.url = url
71
+ this.active = active
72
+ this.description = description
73
+ this.version = version
74
+ }
75
+
76
+ /**
77
+ * Returns the type of the extension.
78
+ * @returns {ExtensionType} The type of the extension
79
+ * Undefined means its not extending any known extension by the application.
80
+ */
81
+ type(): ExtensionTypeEnum | undefined {
82
+ return undefined
83
+ }
84
+
85
+ /**
86
+ * Called when the extension is loaded.
87
+ * Any initialization logic for the extension should be put here.
88
+ */
89
+ abstract onLoad(): void
90
+
91
+ /**
92
+ * Called when the extension is unloaded.
93
+ * Any cleanup logic for the extension should be put here.
94
+ */
95
+ abstract onUnload(): void
96
+
97
+ /**
98
+ * The compatibility of the extension.
99
+ * This is used to check if the extension is compatible with the current environment.
100
+ * @property {Array} platform
101
+ */
102
+ compatibility(): Compatibility | undefined {
103
+ return undefined
104
+ }
105
+
106
+ async registerSettings(settings: SettingComponentProps[]): Promise<void> {
107
+ if (!this.name) {
108
+ console.error('Extension name is not defined')
109
+ return
110
+ }
111
+
112
+ const extensionSettingFolderPath = await joinPath([
113
+ await getJanDataFolderPath(),
114
+ 'settings',
115
+ this.name,
116
+ ])
117
+ settings.forEach((setting) => {
118
+ setting.extensionName = this.name
119
+ })
120
+ try {
121
+ await fs.mkdir(extensionSettingFolderPath)
122
+ const settingFilePath = await joinPath([extensionSettingFolderPath, this.settingFileName])
123
+
124
+ if (await fs.existsSync(settingFilePath)) return
125
+ await fs.writeFileSync(settingFilePath, JSON.stringify(settings, null, 2))
126
+ } catch (err) {
127
+ console.error(err)
128
+ }
129
+ }
130
+
131
+ async getSetting<T>(key: string, defaultValue: T) {
132
+ const keySetting = (await this.getSettings()).find((setting) => setting.key === key)
133
+
134
+ const value = keySetting?.controllerProps.value
135
+ return (value as T) ?? defaultValue
136
+ }
137
+
138
+ onSettingUpdate<T>(key: string, value: T) {
139
+ return
140
+ }
141
+
142
+ /**
143
+ * Determine if the prerequisites for the extension are installed.
144
+ *
145
+ * @returns {boolean} true if the prerequisites are installed, false otherwise.
146
+ */
147
+ async installationState(): Promise<InstallationState> {
148
+ return 'NotRequired'
149
+ }
150
+
151
+ /**
152
+ * Install the prerequisites for the extension.
153
+ *
154
+ * @returns {Promise<void>}
155
+ */
156
+ async install(): Promise<void> {
157
+ return
158
+ }
159
+
160
+ async getSettings(): Promise<SettingComponentProps[]> {
161
+ if (!this.name) return []
162
+
163
+ const settingPath = await joinPath([
164
+ await getJanDataFolderPath(),
165
+ this.settingFolderName,
166
+ this.name,
167
+ this.settingFileName,
168
+ ])
169
+
170
+ try {
171
+ const content = await fs.readFileSync(settingPath, 'utf-8')
172
+ const settings: SettingComponentProps[] = JSON.parse(content)
173
+ return settings
174
+ } catch (err) {
175
+ console.warn(err)
176
+ return []
177
+ }
178
+ }
179
+
180
+ async updateSettings(componentProps: Partial<SettingComponentProps>[]): Promise<void> {
181
+ if (!this.name) return
182
+
183
+ const settings = await this.getSettings()
184
+
185
+ const updatedSettings = settings.map((setting) => {
186
+ const updatedSetting = componentProps.find(
187
+ (componentProp) => componentProp.key === setting.key
188
+ )
189
+ if (updatedSetting && updatedSetting.controllerProps) {
190
+ setting.controllerProps.value = updatedSetting.controllerProps.value
191
+ }
192
+ return setting
193
+ })
194
+
195
+ const settingPath = await joinPath([
196
+ await getJanDataFolderPath(),
197
+ this.settingFolderName,
198
+ this.name,
199
+ this.settingFileName,
200
+ ])
201
+
202
+ await fs.writeFileSync(settingPath, JSON.stringify(updatedSettings, null, 2))
203
+
204
+ updatedSettings.forEach((setting) => {
205
+ this.onSettingUpdate<typeof setting.controllerProps.value>(
206
+ setting.key,
207
+ setting.controllerProps.value
208
+ )
209
+ })
210
+ }
211
+ }