Commit ·
3459571
0
Parent(s):
fc
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .devcontainer/devcontainer.json +4 -0
- .dockerignore +1 -0
- .github/ISSUE_TEMPLATE/bug_report.yml +82 -0
- .github/ISSUE_TEMPLATE/config.yml +7 -0
- .github/ISSUE_TEMPLATE/documentation-request.md +17 -0
- .github/ISSUE_TEMPLATE/epic-request.md +25 -0
- .github/ISSUE_TEMPLATE/feature_request.yml +44 -0
- .github/pull_request_template.md +14 -0
- .github/release-drafter.yml +24 -0
- .github/scripts/auto-sign.sh +12 -0
- .github/workflows/auto-assign-author.yml +14 -0
- .github/workflows/auto-assign-milestone.yml +46 -0
- .github/workflows/auto-label-conventional-commits.yaml +35 -0
- .github/workflows/jan-electron-build-nightly.yml +156 -0
- .github/workflows/jan-electron-build.yml +138 -0
- .github/workflows/jan-electron-linter-and-test.yml +321 -0
- .github/workflows/jan-server-build-nightly.yml +40 -0
- .github/workflows/jan-server-build.yml +30 -0
- .github/workflows/nightly-integrate-cortex-cpp.yml +127 -0
- .github/workflows/template-build-jan-server.yml +39 -0
- .github/workflows/template-build-linux-x64.yml +116 -0
- .github/workflows/template-build-macos-arm64.yml +161 -0
- .github/workflows/template-build-macos-x64.yml +161 -0
- .github/workflows/template-build-windows-x64.yml +144 -0
- .github/workflows/template-get-update-version.yml +58 -0
- .github/workflows/template-noti-discord-and-update-url-readme.yml +57 -0
- .gitignore +41 -0
- .husky/pre-commit +4 -0
- .prettierignore +5 -0
- .prettierrc +7 -0
- Dockerfile +60 -0
- Dockerfile.gpu +87 -0
- LICENSE +660 -0
- Makefile +155 -0
- README.md +352 -0
- charts/server/Chart.lock +6 -0
- charts/server/Chart.yaml +10 -0
- charts/server/charts/common-0.1.2.tgz +0 -0
- charts/server/config.json +4 -0
- charts/server/values.yaml +256 -0
- core/.editorconfig +13 -0
- core/.gitignore +9 -0
- core/README.md +69 -0
- core/jest.config.js +7 -0
- core/package.json +64 -0
- core/rollup.config.ts +85 -0
- core/src/@global/index.d.ts +10 -0
- core/src/browser/core.ts +165 -0
- core/src/browser/events.ts +35 -0
- 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 |
+

|
| 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 |
+

|
| 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 |
+
}
|