canvas-chat 0.1.48__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- canvas_chat-0.1.48/.eslintrc.json +29 -0
- canvas_chat-0.1.48/.github/dependabot.yml +17 -0
- canvas_chat-0.1.48/.github/workflows/auto-release.yaml +206 -0
- canvas_chat-0.1.48/.github/workflows/code-style.yaml +30 -0
- canvas_chat-0.1.48/.github/workflows/docs.yaml +80 -0
- canvas_chat-0.1.48/.github/workflows/modal-deploy.yaml +163 -0
- canvas_chat-0.1.48/.github/workflows/tests.yaml +69 -0
- canvas_chat-0.1.48/.gitignore +183 -0
- canvas_chat-0.1.48/.llamabot/.gitignore +2 -0
- canvas_chat-0.1.48/.llamabot/message_log.db +0 -0
- canvas_chat-0.1.48/.markdownlint.jsonc +4 -0
- canvas_chat-0.1.48/.pre-commit-config.yaml +37 -0
- canvas_chat-0.1.48/.prettierrc +10 -0
- canvas_chat-0.1.48/.vscode/settings.json +22 -0
- canvas_chat-0.1.48/AGENTS.md +817 -0
- canvas_chat-0.1.48/PKG-INFO +217 -0
- canvas_chat-0.1.48/README.md +189 -0
- canvas_chat-0.1.48/config.example.yaml +175 -0
- canvas_chat-0.1.48/config.test.yaml +10 -0
- canvas_chat-0.1.48/docs/CONTRIBUTING.md +100 -0
- canvas_chat-0.1.48/docs/explanation/admin-mode-security.md +195 -0
- canvas_chat-0.1.48/docs/explanation/auto-layout.md +140 -0
- canvas_chat-0.1.48/docs/explanation/committee-architecture.md +322 -0
- canvas_chat-0.1.48/docs/explanation/matrix-evaluation.md +135 -0
- canvas_chat-0.1.48/docs/explanation/matrix-resize-behavior.md +152 -0
- canvas_chat-0.1.48/docs/explanation/node-protocols.md +211 -0
- canvas_chat-0.1.48/docs/explanation/streaming-architecture.md +72 -0
- canvas_chat-0.1.48/docs/explanation/url-fetching.md +73 -0
- canvas_chat-0.1.48/docs/explanation/webrtc-signaling.md +142 -0
- canvas_chat-0.1.48/docs/how-to/admin-mode.md +204 -0
- canvas_chat-0.1.48/docs/how-to/create-custom-node-plugins.md +387 -0
- canvas_chat-0.1.48/docs/how-to/deep-research.md +252 -0
- canvas_chat-0.1.48/docs/how-to/highlight-and-branch.md +268 -0
- canvas_chat-0.1.48/docs/how-to/import-pdfs.md +67 -0
- canvas_chat-0.1.48/docs/how-to/llm-committee.md +307 -0
- canvas_chat-0.1.48/docs/how-to/navigate-nodes.md +46 -0
- canvas_chat-0.1.48/docs/how-to/use-images.md +141 -0
- canvas_chat-0.1.48/docs/how-to/use-matrix-evaluation.md +94 -0
- canvas_chat-0.1.48/docs/how-to/web-search.md +123 -0
- canvas_chat-0.1.48/docs/index.md +118 -0
- canvas_chat-0.1.48/docs/reference/keyboard-shortcuts.md +178 -0
- canvas_chat-0.1.48/docs/reference/search-api.md +152 -0
- canvas_chat-0.1.48/docs/releases/.gitkeep +0 -0
- canvas_chat-0.1.48/docs/releases/v0.1.0.md +92 -0
- canvas_chat-0.1.48/docs/releases/v0.1.1.md +21 -0
- canvas_chat-0.1.48/docs/releases/v0.1.10.md +20 -0
- canvas_chat-0.1.48/docs/releases/v0.1.11.md +20 -0
- canvas_chat-0.1.48/docs/releases/v0.1.12.md +24 -0
- canvas_chat-0.1.48/docs/releases/v0.1.13.md +21 -0
- canvas_chat-0.1.48/docs/releases/v0.1.14.md +19 -0
- canvas_chat-0.1.48/docs/releases/v0.1.15.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.16.md +23 -0
- canvas_chat-0.1.48/docs/releases/v0.1.17.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.18.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.19.md +18 -0
- canvas_chat-0.1.48/docs/releases/v0.1.2.md +17 -0
- canvas_chat-0.1.48/docs/releases/v0.1.20.md +24 -0
- canvas_chat-0.1.48/docs/releases/v0.1.21.md +18 -0
- canvas_chat-0.1.48/docs/releases/v0.1.22.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.23.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.24.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.25.md +25 -0
- canvas_chat-0.1.48/docs/releases/v0.1.26.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.27.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.28.md +19 -0
- canvas_chat-0.1.48/docs/releases/v0.1.29.md +20 -0
- canvas_chat-0.1.48/docs/releases/v0.1.3.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.30.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.31.md +20 -0
- canvas_chat-0.1.48/docs/releases/v0.1.32.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.33.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.34.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.35.md +20 -0
- canvas_chat-0.1.48/docs/releases/v0.1.36.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.37.md +28 -0
- canvas_chat-0.1.48/docs/releases/v0.1.38.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.39.md +17 -0
- canvas_chat-0.1.48/docs/releases/v0.1.4.md +18 -0
- canvas_chat-0.1.48/docs/releases/v0.1.40.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.41.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.42.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.43.md +15 -0
- canvas_chat-0.1.48/docs/releases/v0.1.44.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.45.md +20 -0
- canvas_chat-0.1.48/docs/releases/v0.1.46.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.47.md +17 -0
- canvas_chat-0.1.48/docs/releases/v0.1.48.md +26 -0
- canvas_chat-0.1.48/docs/releases/v0.1.5.md +16 -0
- canvas_chat-0.1.48/docs/releases/v0.1.6.md +17 -0
- canvas_chat-0.1.48/docs/releases/v0.1.7.md +17 -0
- canvas_chat-0.1.48/docs/releases/v0.1.8.md +19 -0
- canvas_chat-0.1.48/docs/releases/v0.1.9.md +17 -0
- canvas_chat-0.1.48/mkdocs.yml +124 -0
- canvas_chat-0.1.48/modal_app.py +53 -0
- canvas_chat-0.1.48/package-lock.json +2056 -0
- canvas_chat-0.1.48/package.json +20 -0
- canvas_chat-0.1.48/pixi.lock +5524 -0
- canvas_chat-0.1.48/pyproject.toml +79 -0
- canvas_chat-0.1.48/src/canvas_chat/__init__.py +30 -0
- canvas_chat-0.1.48/src/canvas_chat/__main__.py +152 -0
- canvas_chat-0.1.48/src/canvas_chat/app.py +3618 -0
- canvas_chat-0.1.48/src/canvas_chat/config.py +279 -0
- canvas_chat-0.1.48/src/canvas_chat/static/css/base.css +151 -0
- canvas_chat-0.1.48/src/canvas_chat/static/css/canvas.css +150 -0
- canvas_chat-0.1.48/src/canvas_chat/static/css/components.css +1075 -0
- canvas_chat-0.1.48/src/canvas_chat/static/css/input.css +119 -0
- canvas_chat-0.1.48/src/canvas_chat/static/css/matrix.css +312 -0
- canvas_chat-0.1.48/src/canvas_chat/static/css/modals.css +1114 -0
- canvas_chat-0.1.48/src/canvas_chat/static/css/nodes.css +1647 -0
- canvas_chat-0.1.48/src/canvas_chat/static/css/style.css +30 -0
- canvas_chat-0.1.48/src/canvas_chat/static/css/toolbar.css +311 -0
- canvas_chat-0.1.48/src/canvas_chat/static/index.html +972 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/app.js +5524 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/canvas.js +4087 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/chat.js +333 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/committee.js +536 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/crdt-graph.js +1802 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/event-emitter.js +93 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/factcheck.js +708 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/file-upload-handler.js +269 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/flashcards.js +771 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/graph-types.js +530 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/highlight-utils.js +347 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/layout.js +200 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/matrix.js +835 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/modal-manager.js +578 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/node-protocols.js +1351 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/node-registry.js +325 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/plugins/example-poll-node.js +245 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/pyodide-runner.js +513 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/research.js +479 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/search.js +314 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/slash-command-menu.js +298 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/sse.js +182 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/storage.js +571 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/undo-manager.js +76 -0
- canvas_chat-0.1.48/src/canvas_chat/static/js/utils.js +437 -0
- canvas_chat-0.1.48/tests/__init__.py +0 -0
- canvas_chat-0.1.48/tests/run_tests.js +122 -0
- canvas_chat-0.1.48/tests/test_app_init.js +201 -0
- canvas_chat-0.1.48/tests/test_canvas_helpers.js +136 -0
- canvas_chat-0.1.48/tests/test_config.py +586 -0
- canvas_chat-0.1.48/tests/test_crdt_graph.js +640 -0
- canvas_chat-0.1.48/tests/test_flashcards.js +396 -0
- canvas_chat-0.1.48/tests/test_graph_types.js +190 -0
- canvas_chat-0.1.48/tests/test_helpers/README.md +88 -0
- canvas_chat-0.1.48/tests/test_helpers/method-binding-test.js +159 -0
- canvas_chat-0.1.48/tests/test_layout.js +199 -0
- canvas_chat-0.1.48/tests/test_matrix.js +436 -0
- canvas_chat-0.1.48/tests/test_models.py +498 -0
- canvas_chat-0.1.48/tests/test_node_protocols.js +665 -0
- canvas_chat-0.1.48/tests/test_node_registry.js +368 -0
- canvas_chat-0.1.48/tests/test_plugin_registration.js +309 -0
- canvas_chat-0.1.48/tests/test_search.js +263 -0
- canvas_chat-0.1.48/tests/test_setup.js +319 -0
- canvas_chat-0.1.48/tests/test_storage.js +808 -0
- canvas_chat-0.1.48/tests/test_ui.js +1019 -0
- canvas_chat-0.1.48/tests/test_utils.js +153 -0
- canvas_chat-0.1.48/tests/test_utils.py +73 -0
- canvas_chat-0.1.48/tests/test_utils_basic.js +409 -0
- canvas_chat-0.1.48/tests/test_utils_messages.js +335 -0
- canvas_chat-0.1.48/uv.lock +4003 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"es2022": true
|
|
5
|
+
},
|
|
6
|
+
"parserOptions": {
|
|
7
|
+
"ecmaVersion": 2022,
|
|
8
|
+
"sourceType": "module"
|
|
9
|
+
},
|
|
10
|
+
"globals": {
|
|
11
|
+
"marked": "readonly",
|
|
12
|
+
"katex": "readonly",
|
|
13
|
+
"markedKatex": "readonly",
|
|
14
|
+
"Y": "readonly",
|
|
15
|
+
"IndexeddbPersistence": "readonly",
|
|
16
|
+
"WebrtcProvider": "readonly",
|
|
17
|
+
"pyodideRunner": "readonly"
|
|
18
|
+
},
|
|
19
|
+
"rules": {
|
|
20
|
+
"no-undef": "error",
|
|
21
|
+
"no-unused-vars": ["warn", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
|
|
22
|
+
"no-dupe-keys": "error",
|
|
23
|
+
"no-duplicate-case": "error",
|
|
24
|
+
"no-empty": "warn",
|
|
25
|
+
"no-unreachable": "error",
|
|
26
|
+
"eqeqeq": ["warn", "smart"],
|
|
27
|
+
"no-var": "warn"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Dependabot configuration
|
|
2
|
+
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
3
|
+
|
|
4
|
+
version: 2
|
|
5
|
+
updates:
|
|
6
|
+
# Keep GitHub Actions up to date
|
|
7
|
+
- package-ecosystem: "github-actions"
|
|
8
|
+
directory: "/"
|
|
9
|
+
schedule:
|
|
10
|
+
interval: "weekly"
|
|
11
|
+
day: "monday"
|
|
12
|
+
commit-message:
|
|
13
|
+
prefix: "ci"
|
|
14
|
+
labels:
|
|
15
|
+
- "dependencies"
|
|
16
|
+
- "github-actions"
|
|
17
|
+
open-pull-requests-limit: 5
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
name: Auto-release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Automatic patch release after tests pass on main.
|
|
5
|
+
# This triggers whenever the "Tests" workflow completes.
|
|
6
|
+
# The job-level `if` condition ensures we only release when:
|
|
7
|
+
# 1. Tests passed (conclusion == 'success')
|
|
8
|
+
# 2. It was a push event (not a PR) - i.e., code was merged to main
|
|
9
|
+
workflow_run:
|
|
10
|
+
workflows: ["Tests"]
|
|
11
|
+
types:
|
|
12
|
+
- completed
|
|
13
|
+
branches:
|
|
14
|
+
- main
|
|
15
|
+
|
|
16
|
+
# Manual release for minor/major versions.
|
|
17
|
+
# To cut a new release, navigate to the Actions section of the repo
|
|
18
|
+
# and select this workflow (Auto-release) on the right hand side.
|
|
19
|
+
# Then, click "Run workflow" and select major, minor, or patch.
|
|
20
|
+
workflow_dispatch:
|
|
21
|
+
inputs:
|
|
22
|
+
version_name:
|
|
23
|
+
description: "One of major, minor, or patch"
|
|
24
|
+
required: true
|
|
25
|
+
type: choice
|
|
26
|
+
options:
|
|
27
|
+
- major
|
|
28
|
+
- minor
|
|
29
|
+
- patch
|
|
30
|
+
|
|
31
|
+
permissions:
|
|
32
|
+
contents: write
|
|
33
|
+
id-token: write
|
|
34
|
+
|
|
35
|
+
env:
|
|
36
|
+
DEFAULT_VERSION_NAME: patch
|
|
37
|
+
|
|
38
|
+
jobs:
|
|
39
|
+
release:
|
|
40
|
+
name: Create a new release
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
# Run if:
|
|
43
|
+
# 1. Manual trigger (workflow_dispatch), OR
|
|
44
|
+
# 2. Automatic trigger where deploy passed AND it was a push (not PR)
|
|
45
|
+
if: |
|
|
46
|
+
github.event_name == 'workflow_dispatch' ||
|
|
47
|
+
(github.event.workflow_run.conclusion == 'success' &&
|
|
48
|
+
github.event.workflow_run.event == 'push')
|
|
49
|
+
|
|
50
|
+
steps:
|
|
51
|
+
- name: Checkout repository
|
|
52
|
+
uses: actions/checkout@v6
|
|
53
|
+
with:
|
|
54
|
+
fetch-depth: 0
|
|
55
|
+
fetch-tags: true
|
|
56
|
+
|
|
57
|
+
- name: Pull latest commits of main branch
|
|
58
|
+
run: |
|
|
59
|
+
git checkout main
|
|
60
|
+
git pull
|
|
61
|
+
|
|
62
|
+
- name: Check if already released
|
|
63
|
+
id: check_release
|
|
64
|
+
run: |
|
|
65
|
+
CURRENT_COMMIT=$(git rev-parse HEAD)
|
|
66
|
+
echo "Current commit: $CURRENT_COMMIT"
|
|
67
|
+
if git tag --points-at $CURRENT_COMMIT | grep -q "^v"; then
|
|
68
|
+
echo "already_released=true" >> $GITHUB_OUTPUT
|
|
69
|
+
echo "This commit already has a release tag. Will skip release."
|
|
70
|
+
git tag --points-at $CURRENT_COMMIT
|
|
71
|
+
else
|
|
72
|
+
echo "already_released=false" >> $GITHUB_OUTPUT
|
|
73
|
+
echo "No release tag found. Proceeding with release."
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
- name: Setup Python environment
|
|
77
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
78
|
+
uses: actions/setup-python@v6
|
|
79
|
+
with:
|
|
80
|
+
python-version: "3.12"
|
|
81
|
+
|
|
82
|
+
- name: Install uv
|
|
83
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
84
|
+
uses: astral-sh/setup-uv@v7
|
|
85
|
+
|
|
86
|
+
- name: Set version name
|
|
87
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
88
|
+
run: echo "VERSION_NAME=${{ github.event.inputs.version_name || env.DEFAULT_VERSION_NAME }}" >> $GITHUB_ENV
|
|
89
|
+
|
|
90
|
+
- name: Store current version number
|
|
91
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
92
|
+
run: echo "current_version=$(uv version --short)" >> $GITHUB_ENV
|
|
93
|
+
|
|
94
|
+
- name: Dry run uv version bump
|
|
95
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
96
|
+
run: uv version --bump ${{ env.VERSION_NAME }} --dry-run --verbose
|
|
97
|
+
|
|
98
|
+
- name: Store new version number
|
|
99
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
100
|
+
run: echo "version_number=$(uv version --bump ${{ env.VERSION_NAME }} --dry-run --short)" >> $GITHUB_ENV
|
|
101
|
+
|
|
102
|
+
- name: Display new version number
|
|
103
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
104
|
+
run: |
|
|
105
|
+
echo "version_name: ${{ env.VERSION_NAME }}"
|
|
106
|
+
echo "version_number: v${{ env.version_number }}"
|
|
107
|
+
|
|
108
|
+
- name: Ensure repo status is clean
|
|
109
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
110
|
+
run: git status
|
|
111
|
+
|
|
112
|
+
- name: Configure Git
|
|
113
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
114
|
+
run: |
|
|
115
|
+
git config user.name github-actions
|
|
116
|
+
git config user.email github-actions@github.com
|
|
117
|
+
|
|
118
|
+
- name: Setup pixi
|
|
119
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
120
|
+
uses: prefix-dev/setup-pixi@v0.9.3
|
|
121
|
+
with:
|
|
122
|
+
run-install: false
|
|
123
|
+
|
|
124
|
+
- name: Install llamabot
|
|
125
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
126
|
+
run: uv tool install llamabot[cli]
|
|
127
|
+
|
|
128
|
+
- name: Run uv version bump
|
|
129
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
130
|
+
run: uv version --bump ${{ env.VERSION_NAME }} --verbose
|
|
131
|
+
|
|
132
|
+
- name: Create version tag
|
|
133
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
134
|
+
run: git tag -a "v${{ env.version_number }}" -m "Release v${{ env.version_number }}"
|
|
135
|
+
|
|
136
|
+
- name: Write release notes
|
|
137
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
138
|
+
env:
|
|
139
|
+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
140
|
+
run: |
|
|
141
|
+
llamabot configure default-model --model-name="gpt-4.1-mini"
|
|
142
|
+
llamabot git write-release-notes
|
|
143
|
+
# Verify the release notes file was created
|
|
144
|
+
if [ ! -f "docs/releases/v${{ env.version_number }}.md" ]; then
|
|
145
|
+
echo "Error: llamabot git write-release-notes did not create docs/releases/v${{ env.version_number }}.md"
|
|
146
|
+
echo "This indicates llamabot failed or the file was not generated."
|
|
147
|
+
exit 1
|
|
148
|
+
fi
|
|
149
|
+
echo "Release notes file created: docs/releases/v${{ env.version_number }}.md"
|
|
150
|
+
|
|
151
|
+
- name: Run pre-commit to fix any formatting issues
|
|
152
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
153
|
+
run: |
|
|
154
|
+
# First run applies auto-fixes (may fail if fixes are needed)
|
|
155
|
+
uvx pre-commit run --all-files || true
|
|
156
|
+
# Stage all files (new and modified) including any fixes pre-commit applied
|
|
157
|
+
git add .
|
|
158
|
+
# Second run verifies all checks pass
|
|
159
|
+
uvx pre-commit run --all-files
|
|
160
|
+
|
|
161
|
+
- name: Commit version bump, release notes, and lock file
|
|
162
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
163
|
+
run: |
|
|
164
|
+
# All files are already staged from the pre-commit step
|
|
165
|
+
git commit -m "Bump version: ${{ env.current_version }} → ${{ env.version_number }}
|
|
166
|
+
|
|
167
|
+
Add release notes for v${{ env.version_number }}"
|
|
168
|
+
|
|
169
|
+
- name: Verify tag creation
|
|
170
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
171
|
+
run: git tag | grep "v${{ env.version_number }}"
|
|
172
|
+
|
|
173
|
+
- name: Build package
|
|
174
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
175
|
+
run: uv build --sdist --wheel
|
|
176
|
+
|
|
177
|
+
- name: Publish package (trusted publishing)
|
|
178
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
179
|
+
run: uv publish --trusted-publishing always
|
|
180
|
+
|
|
181
|
+
- name: Push changes with tags
|
|
182
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
183
|
+
run: |
|
|
184
|
+
git push && git push --tags
|
|
185
|
+
|
|
186
|
+
- name: Verify release notes file exists before creating release
|
|
187
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
188
|
+
run: |
|
|
189
|
+
if [ ! -f "docs/releases/v${{ env.version_number }}.md" ]; then
|
|
190
|
+
echo "Error: Release notes file docs/releases/v${{ env.version_number }}.md does not exist"
|
|
191
|
+
echo "This should have been created in the 'Write release notes' step."
|
|
192
|
+
exit 1
|
|
193
|
+
fi
|
|
194
|
+
echo "Release notes file verified: docs/releases/v${{ env.version_number }}.md"
|
|
195
|
+
|
|
196
|
+
- name: Create release in GitHub repo
|
|
197
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
198
|
+
uses: ncipollo/release-action@v1
|
|
199
|
+
with:
|
|
200
|
+
bodyFile: "docs/releases/v${{ env.version_number }}.md"
|
|
201
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
202
|
+
tag: v${{ env.version_number }}
|
|
203
|
+
|
|
204
|
+
- name: Ensure complete
|
|
205
|
+
if: steps.check_release.outputs.already_released == 'false'
|
|
206
|
+
run: echo "Auto-release complete!"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Run code style checks on each pull request.
|
|
2
|
+
name: Code style checks
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
pull_request:
|
|
6
|
+
push:
|
|
7
|
+
branches:
|
|
8
|
+
- main
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
linting:
|
|
12
|
+
env:
|
|
13
|
+
# Configure a constant location for the uv cache
|
|
14
|
+
UV_CACHE_DIR: /tmp/.uv-cache
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v7
|
|
21
|
+
|
|
22
|
+
- name: Setup Pixi Environment
|
|
23
|
+
uses: prefix-dev/setup-pixi@v0.9.3
|
|
24
|
+
with:
|
|
25
|
+
pixi-version: latest
|
|
26
|
+
cache: true
|
|
27
|
+
cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }}
|
|
28
|
+
|
|
29
|
+
- name: Run pre-commit
|
|
30
|
+
run: uvx pre-commit run --all-files
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: Build and deploy documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- 'docs/**'
|
|
9
|
+
- 'mkdocs.yml'
|
|
10
|
+
- '.github/workflows/docs.yaml'
|
|
11
|
+
pull_request:
|
|
12
|
+
branches:
|
|
13
|
+
- main
|
|
14
|
+
paths:
|
|
15
|
+
- 'docs/**'
|
|
16
|
+
- 'mkdocs.yml'
|
|
17
|
+
- '.github/workflows/docs.yaml'
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
pages: write
|
|
22
|
+
id-token: write
|
|
23
|
+
pull-requests: write
|
|
24
|
+
|
|
25
|
+
# Allow only one concurrent deployment
|
|
26
|
+
concurrency:
|
|
27
|
+
group: 'pages'
|
|
28
|
+
cancel-in-progress: false
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
build-docs:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
name: Build documentation
|
|
34
|
+
|
|
35
|
+
defaults:
|
|
36
|
+
run:
|
|
37
|
+
shell: bash -l {0}
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- name: Checkout repository
|
|
41
|
+
uses: actions/checkout@v6
|
|
42
|
+
with:
|
|
43
|
+
fetch-depth: 0
|
|
44
|
+
|
|
45
|
+
- name: Setup Pixi Environment
|
|
46
|
+
uses: prefix-dev/setup-pixi@v0.9.3
|
|
47
|
+
with:
|
|
48
|
+
pixi-version: latest
|
|
49
|
+
cache: true
|
|
50
|
+
cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }}
|
|
51
|
+
|
|
52
|
+
- name: Build docs
|
|
53
|
+
run: pixi run -e docs docs-build
|
|
54
|
+
|
|
55
|
+
- name: Verify build output
|
|
56
|
+
run: |
|
|
57
|
+
echo "✓ Site directory contents:"
|
|
58
|
+
ls -la ./site
|
|
59
|
+
echo "✓ Build verification passed"
|
|
60
|
+
|
|
61
|
+
- name: Upload artifact
|
|
62
|
+
if: github.event_name == 'push' && github.ref_name == 'main'
|
|
63
|
+
uses: actions/upload-pages-artifact@v3
|
|
64
|
+
with:
|
|
65
|
+
path: ./site
|
|
66
|
+
|
|
67
|
+
deploy:
|
|
68
|
+
if: github.event_name == 'push' && github.ref_name == 'main'
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
needs: build-docs
|
|
71
|
+
name: Deploy to GitHub Pages
|
|
72
|
+
|
|
73
|
+
environment:
|
|
74
|
+
name: github-pages
|
|
75
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
76
|
+
|
|
77
|
+
steps:
|
|
78
|
+
- name: Deploy to GitHub Pages
|
|
79
|
+
id: deployment
|
|
80
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
name: Deploy to Modal
|
|
2
|
+
|
|
3
|
+
permissions:
|
|
4
|
+
contents: read
|
|
5
|
+
issues: write
|
|
6
|
+
pull-requests: write
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches:
|
|
11
|
+
- main
|
|
12
|
+
paths:
|
|
13
|
+
- 'src/**'
|
|
14
|
+
- 'modal_app.py'
|
|
15
|
+
- 'pyproject.toml'
|
|
16
|
+
- 'pixi.lock'
|
|
17
|
+
- '.github/workflows/modal-deploy.yaml'
|
|
18
|
+
pull_request:
|
|
19
|
+
types: [opened, synchronize, reopened]
|
|
20
|
+
paths:
|
|
21
|
+
- 'src/**'
|
|
22
|
+
- 'modal_app.py'
|
|
23
|
+
- 'pyproject.toml'
|
|
24
|
+
- 'pixi.lock'
|
|
25
|
+
- '.github/workflows/modal-deploy.yaml'
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
deploy:
|
|
29
|
+
name: Deploy Canvas Chat
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
env:
|
|
32
|
+
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
|
|
33
|
+
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
|
|
34
|
+
# Deployed app URLs (not Modal dashboard URLs)
|
|
35
|
+
TEST_APP_URL: "https://ericmjl-test--canvas-chat-fastapi-app.modal.run"
|
|
36
|
+
MAIN_APP_URL: "https://ericmjl--canvas-chat-fastapi-app.modal.run"
|
|
37
|
+
outputs:
|
|
38
|
+
test_url: ${{ steps.deploy-test.outputs.url }}
|
|
39
|
+
main_url: ${{ steps.deploy-main.outputs.url }}
|
|
40
|
+
test_app_url: ${{ steps.deploy-test.outputs.app_url }}
|
|
41
|
+
main_app_url: ${{ steps.deploy-main.outputs.app_url }}
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- name: Checkout repository
|
|
45
|
+
uses: actions/checkout@v6
|
|
46
|
+
|
|
47
|
+
- name: Install uv
|
|
48
|
+
uses: astral-sh/setup-uv@v7
|
|
49
|
+
|
|
50
|
+
- name: Deploy to test environment (PR)
|
|
51
|
+
if: github.event_name == 'pull_request'
|
|
52
|
+
id: deploy-test
|
|
53
|
+
run: |
|
|
54
|
+
OUTPUT=$(uv run --with modal modal deploy modal_app.py -e test 2>&1)
|
|
55
|
+
echo "$OUTPUT"
|
|
56
|
+
URL=$(echo "$OUTPUT" | grep -oE 'https://modal\.com/apps/[^ ]+' | head -1)
|
|
57
|
+
echo "url=$URL" >> $GITHUB_OUTPUT
|
|
58
|
+
echo "app_url=$TEST_APP_URL" >> $GITHUB_OUTPUT
|
|
59
|
+
|
|
60
|
+
- name: Deploy to main environment (push to main)
|
|
61
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
62
|
+
id: deploy-main
|
|
63
|
+
run: |
|
|
64
|
+
OUTPUT=$(uv run --with modal modal deploy modal_app.py 2>&1)
|
|
65
|
+
echo "$OUTPUT"
|
|
66
|
+
URL=$(echo "$OUTPUT" | grep -oE 'https://modal\.com/apps/[^ ]+' | head -1)
|
|
67
|
+
echo "url=$URL" >> $GITHUB_OUTPUT
|
|
68
|
+
echo "app_url=$MAIN_APP_URL" >> $GITHUB_OUTPUT
|
|
69
|
+
|
|
70
|
+
- name: Health check (test deploy)
|
|
71
|
+
if: github.event_name == 'pull_request'
|
|
72
|
+
run: |
|
|
73
|
+
URL="${TEST_APP_URL}/health"
|
|
74
|
+
echo "Checking health for $URL"
|
|
75
|
+
for i in 1 2 3 4 5; do
|
|
76
|
+
status=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 --max-time 10 "$URL" || echo "000")
|
|
77
|
+
echo "Attempt $i: HTTP $status"
|
|
78
|
+
if [ "$status" = "200" ]; then
|
|
79
|
+
echo "Deployment healthy"
|
|
80
|
+
exit 0
|
|
81
|
+
fi
|
|
82
|
+
sleep 3
|
|
83
|
+
done
|
|
84
|
+
echo "Deployment health check failed for $URL"
|
|
85
|
+
exit 1
|
|
86
|
+
|
|
87
|
+
- name: Health check (main deploy)
|
|
88
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
89
|
+
run: |
|
|
90
|
+
URL="${MAIN_APP_URL}/health"
|
|
91
|
+
echo "Checking health for $URL"
|
|
92
|
+
for i in 1 2 3 4 5; do
|
|
93
|
+
status=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 --max-time 10 "$URL" || echo "000")
|
|
94
|
+
echo "Attempt $i: HTTP $status"
|
|
95
|
+
if [ "$status" = "200" ]; then
|
|
96
|
+
echo "Deployment healthy"
|
|
97
|
+
exit 0
|
|
98
|
+
fi
|
|
99
|
+
sleep 3
|
|
100
|
+
done
|
|
101
|
+
echo "Deployment health check failed for $URL"
|
|
102
|
+
exit 1
|
|
103
|
+
|
|
104
|
+
- name: Write deployment summary
|
|
105
|
+
run: |
|
|
106
|
+
echo "## 🚀 Modal Deployment" >> $GITHUB_STEP_SUMMARY
|
|
107
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
108
|
+
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
109
|
+
echo "**Environment:** test" >> $GITHUB_STEP_SUMMARY
|
|
110
|
+
echo "**App URL:** ${TEST_APP_URL}" >> $GITHUB_STEP_SUMMARY
|
|
111
|
+
echo "**Dashboard:** ${{ steps.deploy-test.outputs.url }}" >> $GITHUB_STEP_SUMMARY
|
|
112
|
+
else
|
|
113
|
+
echo "**Environment:** main" >> $GITHUB_STEP_SUMMARY
|
|
114
|
+
echo "**App URL:** ${MAIN_APP_URL}" >> $GITHUB_STEP_SUMMARY
|
|
115
|
+
echo "**Dashboard:** ${{ steps.deploy-main.outputs.url }}" >> $GITHUB_STEP_SUMMARY
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
post-pr-comment:
|
|
120
|
+
name: Post PR comment
|
|
121
|
+
runs-on: ubuntu-latest
|
|
122
|
+
needs: deploy
|
|
123
|
+
if: github.event_name == 'pull_request'
|
|
124
|
+
steps:
|
|
125
|
+
- name: Post or update PR comment
|
|
126
|
+
uses: actions/github-script@v8
|
|
127
|
+
with:
|
|
128
|
+
script: |
|
|
129
|
+
const marker = '<!-- modal-deploy-comment -->';
|
|
130
|
+
const appUrl = '${{ needs.deploy.outputs.test_app_url }}';
|
|
131
|
+
const dashboardUrl = '${{ needs.deploy.outputs.test_url }}';
|
|
132
|
+
const body = `${marker}
|
|
133
|
+
## 🚀 Modal Deployment
|
|
134
|
+
|
|
135
|
+
**Environment:** test
|
|
136
|
+
**App URL:** ${appUrl}
|
|
137
|
+
**Dashboard:** ${dashboardUrl}
|
|
138
|
+
|
|
139
|
+
_This comment is automatically updated on each push._`;
|
|
140
|
+
|
|
141
|
+
const { data: comments } = await github.rest.issues.listComments({
|
|
142
|
+
owner: context.repo.owner,
|
|
143
|
+
repo: context.repo.repo,
|
|
144
|
+
issue_number: context.issue.number,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const existing = comments.find(c => c.body.includes(marker));
|
|
148
|
+
|
|
149
|
+
if (existing) {
|
|
150
|
+
await github.rest.issues.updateComment({
|
|
151
|
+
owner: context.repo.owner,
|
|
152
|
+
repo: context.repo.repo,
|
|
153
|
+
comment_id: existing.id,
|
|
154
|
+
body: body,
|
|
155
|
+
});
|
|
156
|
+
} else {
|
|
157
|
+
await github.rest.issues.createComment({
|
|
158
|
+
owner: context.repo.owner,
|
|
159
|
+
repo: context.repo.repo,
|
|
160
|
+
issue_number: context.issue.number,
|
|
161
|
+
body: body,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- "src/**"
|
|
9
|
+
- "tests/**"
|
|
10
|
+
- "pyproject.toml"
|
|
11
|
+
- ".github/workflows/tests.yaml"
|
|
12
|
+
pull_request:
|
|
13
|
+
branches:
|
|
14
|
+
- main
|
|
15
|
+
paths:
|
|
16
|
+
- "src/**"
|
|
17
|
+
- "tests/**"
|
|
18
|
+
- "pyproject.toml"
|
|
19
|
+
- "package.json"
|
|
20
|
+
- "package-lock.json"
|
|
21
|
+
- ".github/workflows/tests.yaml"
|
|
22
|
+
|
|
23
|
+
concurrency:
|
|
24
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
25
|
+
cancel-in-progress: true
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
python-tests:
|
|
29
|
+
name: Python tests (Python ${{ matrix.python-version }})
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
strategy:
|
|
32
|
+
fail-fast: false
|
|
33
|
+
matrix:
|
|
34
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
35
|
+
|
|
36
|
+
steps:
|
|
37
|
+
- name: Checkout repository
|
|
38
|
+
uses: actions/checkout@v6
|
|
39
|
+
|
|
40
|
+
- name: Setup Python
|
|
41
|
+
uses: actions/setup-python@v6
|
|
42
|
+
with:
|
|
43
|
+
python-version: ${{ matrix.python-version }}
|
|
44
|
+
|
|
45
|
+
- name: Install uv
|
|
46
|
+
uses: astral-sh/setup-uv@v7
|
|
47
|
+
|
|
48
|
+
- name: Install dependencies
|
|
49
|
+
run: uv pip install --system -e ".[dev]"
|
|
50
|
+
|
|
51
|
+
- name: Run Python tests
|
|
52
|
+
run: pytest tests/ -v --color=yes
|
|
53
|
+
|
|
54
|
+
javascript-tests:
|
|
55
|
+
name: JavaScript tests
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
|
|
58
|
+
steps:
|
|
59
|
+
- name: Checkout repository
|
|
60
|
+
uses: actions/checkout@v6
|
|
61
|
+
|
|
62
|
+
- name: Install pixi
|
|
63
|
+
uses: prefix-dev/setup-pixi@v0.9.3
|
|
64
|
+
|
|
65
|
+
- name: Install npm dependencies
|
|
66
|
+
run: pixi run npm install
|
|
67
|
+
|
|
68
|
+
- name: Run JavaScript tests
|
|
69
|
+
run: pixi run test-js
|