sk4n 0.1.0__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.
- sk4n-0.1.0/.github/workflows/ci.yml +120 -0
- sk4n-0.1.0/.github/workflows/release.yml +241 -0
- sk4n-0.1.0/.gitignore +232 -0
- sk4n-0.1.0/AGENT.md +97 -0
- sk4n-0.1.0/CHANGELOG.md +9 -0
- sk4n-0.1.0/LICENSE +21 -0
- sk4n-0.1.0/PKG-INFO +247 -0
- sk4n-0.1.0/README.md +220 -0
- sk4n-0.1.0/justfile +36 -0
- sk4n-0.1.0/pyproject.toml +83 -0
- sk4n-0.1.0/scripts/generate_skill_references.py +398 -0
- sk4n-0.1.0/scripts/validate_package.py +135 -0
- sk4n-0.1.0/src/sk4n/__init__.py +1 -0
- sk4n-0.1.0/src/sk4n/__main__.py +4 -0
- sk4n-0.1.0/src/sk4n/academic_calendar.py +116 -0
- sk4n-0.1.0/src/sk4n/canvas/README.md +266 -0
- sk4n-0.1.0/src/sk4n/canvas/__init__.py +4 -0
- sk4n-0.1.0/src/sk4n/canvas/__main__.py +4 -0
- sk4n-0.1.0/src/sk4n/canvas/assignments.py +1792 -0
- sk4n-0.1.0/src/sk4n/canvas/auth.py +182 -0
- sk4n-0.1.0/src/sk4n/canvas/cli.py +1016 -0
- sk4n-0.1.0/src/sk4n/canvas/client.py +696 -0
- sk4n-0.1.0/src/sk4n/canvas/content.py +191 -0
- sk4n-0.1.0/src/sk4n/canvas/fetcher.py +958 -0
- sk4n-0.1.0/src/sk4n/canvas/files.py +341 -0
- sk4n-0.1.0/src/sk4n/canvas/groups.py +54 -0
- sk4n-0.1.0/src/sk4n/canvas/models.py +360 -0
- sk4n-0.1.0/src/sk4n/canvas/modules.py +53 -0
- sk4n-0.1.0/src/sk4n/canvas/pages.py +112 -0
- sk4n-0.1.0/src/sk4n/canvas/people.py +54 -0
- sk4n-0.1.0/src/sk4n/canvas/quiz_content.py +632 -0
- sk4n-0.1.0/src/sk4n/canvas/syllabus.py +80 -0
- sk4n-0.1.0/src/sk4n/canvas/sync.py +592 -0
- sk4n-0.1.0/src/sk4n/canvas/topics.py +165 -0
- sk4n-0.1.0/src/sk4n/canvas/utils.py +368 -0
- sk4n-0.1.0/src/sk4n/cli.py +322 -0
- sk4n-0.1.0/src/sk4n/doctor.py +501 -0
- sk4n-0.1.0/src/sk4n/errors.py +30 -0
- sk4n-0.1.0/src/sk4n/nusmods/README.md +187 -0
- sk4n-0.1.0/src/sk4n/nusmods/__init__.py +5 -0
- sk4n-0.1.0/src/sk4n/nusmods/__main__.py +4 -0
- sk4n-0.1.0/src/sk4n/nusmods/cli.py +1247 -0
- sk4n-0.1.0/src/sk4n/nusmods/client.py +295 -0
- sk4n-0.1.0/src/sk4n/nusmods/schedule.py +840 -0
- sk4n-0.1.0/src/sk4n/paths.py +56 -0
- sk4n-0.1.0/src/sk4n/skill_install.py +601 -0
- sk4n-0.1.0/src/sk4n/skills/nus-canvas/SKILL.md +46 -0
- sk4n-0.1.0/src/sk4n/skills/nus-canvas/agents/openai.yaml +4 -0
- sk4n-0.1.0/src/sk4n/skills/nus-canvas/references/commands.md +254 -0
- sk4n-0.1.0/src/sk4n/skills/nus-canvas/references/low-level.md +43 -0
- sk4n-0.1.0/src/sk4n/skills/nus-talent-connect/SKILL.md +26 -0
- sk4n-0.1.0/src/sk4n/skills/nus-talent-connect/agents/openai.yaml +4 -0
- sk4n-0.1.0/src/sk4n/skills/nus-talent-connect/references/commands.md +280 -0
- sk4n-0.1.0/src/sk4n/skills/nus-talent-connect/references/low-level.md +43 -0
- sk4n-0.1.0/src/sk4n/skills/nusmods/SKILL.md +26 -0
- sk4n-0.1.0/src/sk4n/skills/nusmods/agents/openai.yaml +4 -0
- sk4n-0.1.0/src/sk4n/skills/nusmods/references/commands.md +248 -0
- sk4n-0.1.0/src/sk4n/talent_connect/README.md +291 -0
- sk4n-0.1.0/src/sk4n/talent_connect/__init__.py +6 -0
- sk4n-0.1.0/src/sk4n/talent_connect/__main__.py +4 -0
- sk4n-0.1.0/src/sk4n/talent_connect/auth.py +172 -0
- sk4n-0.1.0/src/sk4n/talent_connect/authenticated_client.py +659 -0
- sk4n-0.1.0/src/sk4n/talent_connect/cli.py +1228 -0
- sk4n-0.1.0/src/sk4n/talent_connect/client.py +349 -0
- sk4n-0.1.0/src/sk4n/talent_connect/storage.py +648 -0
- sk4n-0.1.0/src/sk4n/tools/__init__.py +11 -0
- sk4n-0.1.0/src/sk4n/tools/playwright_cli.py +144 -0
- sk4n-0.1.0/src/sk4n/tools/request.py +259 -0
- sk4n-0.1.0/src/sk4n/tools/shared.py +172 -0
- sk4n-0.1.0/tests/test_canvas.py +1054 -0
- sk4n-0.1.0/tests/test_management_cli.py +308 -0
- sk4n-0.1.0/tests/test_nusmods.py +506 -0
- sk4n-0.1.0/tests/test_paths.py +111 -0
- sk4n-0.1.0/tests/test_playwright_cli.py +156 -0
- sk4n-0.1.0/tests/test_skill_install.py +176 -0
- sk4n-0.1.0/tests/test_skill_references.py +37 -0
- sk4n-0.1.0/tests/test_talent_connect.py +518 -0
- sk4n-0.1.0/uv.lock +1139 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
workflow_call:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
env:
|
|
19
|
+
UV_NO_PROGRESS: "1"
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
tests:
|
|
23
|
+
name: Tests (${{ matrix.os }}, Python ${{ matrix.python-version }})
|
|
24
|
+
runs-on: ${{ matrix.os }}
|
|
25
|
+
timeout-minutes: 15
|
|
26
|
+
strategy:
|
|
27
|
+
fail-fast: true
|
|
28
|
+
matrix:
|
|
29
|
+
include:
|
|
30
|
+
- os: ubuntu-latest
|
|
31
|
+
python-version: "3.11"
|
|
32
|
+
- os: ubuntu-latest
|
|
33
|
+
python-version: "3.12"
|
|
34
|
+
- os: ubuntu-latest
|
|
35
|
+
python-version: "3.13"
|
|
36
|
+
- os: ubuntu-latest
|
|
37
|
+
python-version: "3.14"
|
|
38
|
+
- os: macos-latest
|
|
39
|
+
python-version: "3.14"
|
|
40
|
+
- os: windows-latest
|
|
41
|
+
python-version: "3.14"
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- name: Check out the repository
|
|
45
|
+
uses: actions/checkout@v7
|
|
46
|
+
with:
|
|
47
|
+
persist-credentials: false
|
|
48
|
+
|
|
49
|
+
- name: Install uv and Python
|
|
50
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
51
|
+
with:
|
|
52
|
+
version: "0.11.17"
|
|
53
|
+
python-version: ${{ matrix.python-version }}
|
|
54
|
+
enable-cache: true
|
|
55
|
+
|
|
56
|
+
- name: Install the locked project and development dependencies
|
|
57
|
+
run: uv sync --locked --all-groups
|
|
58
|
+
|
|
59
|
+
- name: Run unit tests
|
|
60
|
+
run: uv run --locked pytest -q
|
|
61
|
+
|
|
62
|
+
source-checks:
|
|
63
|
+
name: Source checks
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
timeout-minutes: 15
|
|
66
|
+
|
|
67
|
+
steps:
|
|
68
|
+
- name: Check out the repository
|
|
69
|
+
uses: actions/checkout@v7
|
|
70
|
+
with:
|
|
71
|
+
persist-credentials: false
|
|
72
|
+
|
|
73
|
+
- name: Install uv and Python
|
|
74
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
75
|
+
with:
|
|
76
|
+
version: "0.11.17"
|
|
77
|
+
python-version: "3.14"
|
|
78
|
+
enable-cache: true
|
|
79
|
+
|
|
80
|
+
- name: Install the locked project and development dependencies
|
|
81
|
+
run: uv sync --locked --all-groups
|
|
82
|
+
|
|
83
|
+
- name: Run Ruff
|
|
84
|
+
run: uv run --locked ruff --config pyproject.toml check .
|
|
85
|
+
|
|
86
|
+
- name: Run Pyright
|
|
87
|
+
run: uv run --locked pyright
|
|
88
|
+
|
|
89
|
+
- name: Check generated CLI references
|
|
90
|
+
run: uv run --locked python scripts/generate_skill_references.py --check
|
|
91
|
+
|
|
92
|
+
package:
|
|
93
|
+
name: Package artifacts
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
timeout-minutes: 20
|
|
96
|
+
|
|
97
|
+
steps:
|
|
98
|
+
- name: Check out the repository
|
|
99
|
+
uses: actions/checkout@v7
|
|
100
|
+
with:
|
|
101
|
+
persist-credentials: false
|
|
102
|
+
|
|
103
|
+
- name: Install uv and the minimum supported Python
|
|
104
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
105
|
+
with:
|
|
106
|
+
version: "0.11.17"
|
|
107
|
+
python-version: "3.11"
|
|
108
|
+
enable-cache: true
|
|
109
|
+
|
|
110
|
+
- name: Install the locked project and development dependencies
|
|
111
|
+
run: uv sync --locked --all-groups
|
|
112
|
+
|
|
113
|
+
- name: Build wheel and source distribution
|
|
114
|
+
run: uv run --locked python -m build
|
|
115
|
+
|
|
116
|
+
- name: Check package metadata
|
|
117
|
+
run: uv run --locked twine check --strict dist/*
|
|
118
|
+
|
|
119
|
+
- name: Inspect and clean-install both artifacts with pip
|
|
120
|
+
run: uv run --locked python scripts/validate_package.py dist
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types:
|
|
6
|
+
- published
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: release-${{ github.event.release.tag_name }}
|
|
13
|
+
cancel-in-progress: false
|
|
14
|
+
|
|
15
|
+
env:
|
|
16
|
+
UV_NO_PROGRESS: "1"
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
ci:
|
|
20
|
+
name: Run CI for the release commit
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
uses: $/.github/workflows/ci.yml
|
|
24
|
+
|
|
25
|
+
build:
|
|
26
|
+
name: Build and validate release artifacts
|
|
27
|
+
needs:
|
|
28
|
+
- ci
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
timeout-minutes: 25
|
|
31
|
+
outputs:
|
|
32
|
+
version: ${{ steps.package-version.outputs.version }}
|
|
33
|
+
|
|
34
|
+
steps:
|
|
35
|
+
- name: Check out the release tag
|
|
36
|
+
uses: actions/checkout@v7
|
|
37
|
+
with:
|
|
38
|
+
ref: ${{ github.event.release.tag_name }}
|
|
39
|
+
persist-credentials: false
|
|
40
|
+
|
|
41
|
+
- name: Install uv and Python
|
|
42
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
43
|
+
with:
|
|
44
|
+
version: "0.11.17"
|
|
45
|
+
python-version: "3.14"
|
|
46
|
+
enable-cache: true
|
|
47
|
+
|
|
48
|
+
- name: Install the locked project and development dependencies
|
|
49
|
+
run: uv sync --locked --all-groups
|
|
50
|
+
|
|
51
|
+
- name: Verify that the release tag matches the package version
|
|
52
|
+
id: package-version
|
|
53
|
+
env:
|
|
54
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
55
|
+
run: |
|
|
56
|
+
package_version="$(uv run --locked python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
|
|
57
|
+
if [[ "$RELEASE_TAG" != "v$package_version" ]]; then
|
|
58
|
+
echo "Release tag $RELEASE_TAG does not match package version $package_version." >&2
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
echo "version=$package_version" >> "$GITHUB_OUTPUT"
|
|
62
|
+
|
|
63
|
+
- name: Audit the locked environment
|
|
64
|
+
run: uv run --locked pip-audit --local --skip-editable --progress-spinner off
|
|
65
|
+
|
|
66
|
+
- name: Audit the allowed runtime dependency range
|
|
67
|
+
run: >-
|
|
68
|
+
uv run --locked pip-audit
|
|
69
|
+
--strict
|
|
70
|
+
--progress-spinner off
|
|
71
|
+
.
|
|
72
|
+
|
|
73
|
+
- name: Build wheel and source distribution
|
|
74
|
+
run: uv run --locked python -m build
|
|
75
|
+
|
|
76
|
+
- name: Check package metadata
|
|
77
|
+
run: uv run --locked twine check --strict dist/*
|
|
78
|
+
|
|
79
|
+
- name: Inspect and clean-install both artifacts with pip
|
|
80
|
+
run: uv run --locked python scripts/validate_package.py dist
|
|
81
|
+
|
|
82
|
+
- name: Store the exact release artifacts
|
|
83
|
+
uses: actions/upload-artifact@v7
|
|
84
|
+
with:
|
|
85
|
+
name: python-package-distributions
|
|
86
|
+
path: dist/
|
|
87
|
+
if-no-files-found: error
|
|
88
|
+
overwrite: true
|
|
89
|
+
retention-days: 90
|
|
90
|
+
|
|
91
|
+
github-release-assets:
|
|
92
|
+
name: Attach artifacts to the GitHub Release
|
|
93
|
+
needs:
|
|
94
|
+
- build
|
|
95
|
+
- publish-pypi
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
timeout-minutes: 10
|
|
98
|
+
permissions:
|
|
99
|
+
contents: write
|
|
100
|
+
|
|
101
|
+
steps:
|
|
102
|
+
- name: Download the release artifacts
|
|
103
|
+
uses: actions/download-artifact@v8
|
|
104
|
+
with:
|
|
105
|
+
name: python-package-distributions
|
|
106
|
+
path: dist/
|
|
107
|
+
|
|
108
|
+
- name: Attach the artifacts
|
|
109
|
+
env:
|
|
110
|
+
GH_TOKEN: ${{ github.token }}
|
|
111
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
112
|
+
run: gh release upload "$RELEASE_TAG" dist/* --clobber --repo "$GITHUB_REPOSITORY"
|
|
113
|
+
|
|
114
|
+
publish-testpypi:
|
|
115
|
+
name: Publish to TestPyPI
|
|
116
|
+
needs:
|
|
117
|
+
- build
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
timeout-minutes: 10
|
|
120
|
+
environment:
|
|
121
|
+
name: testpypi
|
|
122
|
+
url: https://test.pypi.org/p/sk4n
|
|
123
|
+
permissions:
|
|
124
|
+
id-token: write
|
|
125
|
+
|
|
126
|
+
steps:
|
|
127
|
+
- name: Download the release artifacts
|
|
128
|
+
uses: actions/download-artifact@v8
|
|
129
|
+
with:
|
|
130
|
+
name: python-package-distributions
|
|
131
|
+
path: dist/
|
|
132
|
+
|
|
133
|
+
- name: Publish the artifacts to TestPyPI
|
|
134
|
+
uses: pypa/gh-action-pypi-publish@v1.14.2
|
|
135
|
+
with:
|
|
136
|
+
repository-url: https://test.pypi.org/legacy/
|
|
137
|
+
skip-existing: true
|
|
138
|
+
print-hash: true
|
|
139
|
+
attestations: true
|
|
140
|
+
|
|
141
|
+
test-testpypi:
|
|
142
|
+
name: Test TestPyPI (${{ matrix.os }})
|
|
143
|
+
needs:
|
|
144
|
+
- build
|
|
145
|
+
- publish-testpypi
|
|
146
|
+
runs-on: ${{ matrix.os }}
|
|
147
|
+
timeout-minutes: 15
|
|
148
|
+
permissions:
|
|
149
|
+
contents: read
|
|
150
|
+
strategy:
|
|
151
|
+
fail-fast: false
|
|
152
|
+
matrix:
|
|
153
|
+
os:
|
|
154
|
+
- ubuntu-latest
|
|
155
|
+
- macos-latest
|
|
156
|
+
- windows-latest
|
|
157
|
+
|
|
158
|
+
steps:
|
|
159
|
+
- name: Set up Python
|
|
160
|
+
uses: actions/setup-python@v7
|
|
161
|
+
with:
|
|
162
|
+
python-version: "3.14"
|
|
163
|
+
|
|
164
|
+
- name: Download the original release artifacts
|
|
165
|
+
uses: actions/download-artifact@v8
|
|
166
|
+
with:
|
|
167
|
+
name: python-package-distributions
|
|
168
|
+
path: release-dist/
|
|
169
|
+
|
|
170
|
+
- name: Download the published wheel from TestPyPI
|
|
171
|
+
shell: bash
|
|
172
|
+
env:
|
|
173
|
+
PACKAGE_VERSION: ${{ needs.build.outputs.version }}
|
|
174
|
+
run: |
|
|
175
|
+
for attempt in 1 2 3 4 5 6; do
|
|
176
|
+
if python -m pip download \
|
|
177
|
+
--disable-pip-version-check \
|
|
178
|
+
--no-cache-dir \
|
|
179
|
+
--no-deps \
|
|
180
|
+
--index-url https://test.pypi.org/simple/ \
|
|
181
|
+
--dest test-dist \
|
|
182
|
+
"sk4n==$PACKAGE_VERSION"; then
|
|
183
|
+
break
|
|
184
|
+
fi
|
|
185
|
+
if [[ "$attempt" == "6" ]]; then
|
|
186
|
+
exit 1
|
|
187
|
+
fi
|
|
188
|
+
sleep 10
|
|
189
|
+
done
|
|
190
|
+
|
|
191
|
+
- name: Verify that TestPyPI served the original wheel
|
|
192
|
+
run: >-
|
|
193
|
+
python -c
|
|
194
|
+
"from pathlib import Path;
|
|
195
|
+
original=list(Path('release-dist').glob('sk4n-*.whl'));
|
|
196
|
+
published=list(Path('test-dist').glob('sk4n-*.whl'));
|
|
197
|
+
assert len(original) == len(published) == 1;
|
|
198
|
+
assert original[0].read_bytes() == published[0].read_bytes()"
|
|
199
|
+
|
|
200
|
+
- name: Install the TestPyPI wheel with dependencies from PyPI
|
|
201
|
+
shell: bash
|
|
202
|
+
run: python -m pip install --disable-pip-version-check test-dist/sk4n-*.whl
|
|
203
|
+
|
|
204
|
+
- name: Exercise the installed package and console scripts
|
|
205
|
+
shell: bash
|
|
206
|
+
env:
|
|
207
|
+
PACKAGE_VERSION: ${{ needs.build.outputs.version }}
|
|
208
|
+
SK4N_HOME: ${{ runner.temp }}/sk4n-release-smoke
|
|
209
|
+
run: |
|
|
210
|
+
python -c 'import os; from importlib.metadata import version; assert version("sk4n") == os.environ["PACKAGE_VERSION"]'
|
|
211
|
+
sk4n --help
|
|
212
|
+
canvas --help
|
|
213
|
+
nusmods --help
|
|
214
|
+
talent-connect --help
|
|
215
|
+
|
|
216
|
+
publish-pypi:
|
|
217
|
+
name: Publish to PyPI
|
|
218
|
+
needs:
|
|
219
|
+
- build
|
|
220
|
+
- test-testpypi
|
|
221
|
+
runs-on: ubuntu-latest
|
|
222
|
+
timeout-minutes: 10
|
|
223
|
+
environment:
|
|
224
|
+
name: pypi
|
|
225
|
+
url: https://pypi.org/p/sk4n
|
|
226
|
+
permissions:
|
|
227
|
+
id-token: write
|
|
228
|
+
|
|
229
|
+
steps:
|
|
230
|
+
- name: Download the original release artifacts
|
|
231
|
+
uses: actions/download-artifact@v8
|
|
232
|
+
with:
|
|
233
|
+
name: python-package-distributions
|
|
234
|
+
path: dist/
|
|
235
|
+
|
|
236
|
+
- name: Publish the artifacts to PyPI
|
|
237
|
+
uses: pypa/gh-action-pypi-publish@v1.14.2
|
|
238
|
+
with:
|
|
239
|
+
skip-existing: true
|
|
240
|
+
print-hash: true
|
|
241
|
+
attestations: true
|
sk4n-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# pytype static type analyzer
|
|
179
|
+
.pytype/
|
|
180
|
+
|
|
181
|
+
# Cython debug symbols
|
|
182
|
+
cython_debug/
|
|
183
|
+
|
|
184
|
+
# PyCharm
|
|
185
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
186
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
188
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
189
|
+
# .idea/
|
|
190
|
+
|
|
191
|
+
# Abstra
|
|
192
|
+
# Abstra is an AI-powered process automation framework.
|
|
193
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
194
|
+
# Learn more at https://abstra.io/docs
|
|
195
|
+
.abstra/
|
|
196
|
+
|
|
197
|
+
# Visual Studio Code
|
|
198
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
199
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
201
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
202
|
+
# .vscode/
|
|
203
|
+
# Temporary file for partial code execution
|
|
204
|
+
tempCodeRunnerFile.py
|
|
205
|
+
|
|
206
|
+
# Ruff stuff:
|
|
207
|
+
.ruff_cache/
|
|
208
|
+
|
|
209
|
+
# PyPI configuration file
|
|
210
|
+
.pypirc
|
|
211
|
+
|
|
212
|
+
# Marimo
|
|
213
|
+
marimo/_static/
|
|
214
|
+
marimo/_lsp/
|
|
215
|
+
__marimo__/
|
|
216
|
+
|
|
217
|
+
# Streamlit
|
|
218
|
+
.streamlit/secrets.toml
|
|
219
|
+
|
|
220
|
+
temp/
|
|
221
|
+
sessions/
|
|
222
|
+
data/
|
|
223
|
+
.DS_Store
|
|
224
|
+
._*
|
|
225
|
+
desktop.ini
|
|
226
|
+
Thumbs.db
|
|
227
|
+
|
|
228
|
+
.playwright/
|
|
229
|
+
.playwright-cli/
|
|
230
|
+
.claude/
|
|
231
|
+
.agents/
|
|
232
|
+
.agent/
|
sk4n-0.1.0/AGENT.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Maintainer agent guide
|
|
2
|
+
|
|
3
|
+
This file is guidance for agents maintaining this repository. It is not the
|
|
4
|
+
operating prompt for an end-user-facing NUS assistant.
|
|
5
|
+
|
|
6
|
+
nus-canvas, nus-talent-connect and nusmods skills may have been installed to you, those are for end-user-facing NUS assistant.
|
|
7
|
+
|
|
8
|
+
## Repository map
|
|
9
|
+
|
|
10
|
+
- `src/sk4n/canvas/` provides authenticated, read-only Canvas queries, targeted cache
|
|
11
|
+
refreshes, bulk synchronization, direct authenticated API
|
|
12
|
+
access, and authenticated `@playwright/cli` sessions.
|
|
13
|
+
- `src/sk4n/talent_connect/` provides public and authenticated Kinobi job/company
|
|
14
|
+
access, local SQLite persistence, direct authenticated API access, and
|
|
15
|
+
authenticated `@playwright/cli` sessions.
|
|
16
|
+
- `src/sk4n/nusmods/` uses public NUSMods APIs and does not need an authentication flow.
|
|
17
|
+
- `src/sk4n/tools/` contains shared request, saved-session, and browser-session helpers.
|
|
18
|
+
- `tests/` contains the unit suite. Keep application-specific behavior in its
|
|
19
|
+
package and put genuinely shared behavior in `src/sk4n/tools/`.
|
|
20
|
+
|
|
21
|
+
For check / build / test, refer to the justfile under repo root.
|
|
22
|
+
Prefer running the just commands like `just check` as is.
|
|
23
|
+
|
|
24
|
+
## Authentication comes first
|
|
25
|
+
|
|
26
|
+
Before any Canvas or TalentConnect task that may contact the real service,
|
|
27
|
+
always check authentication status first:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv run canvas auth status
|
|
31
|
+
uv run talent-connect auth status
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If the relevant command reports unauthenticated and the task needs actual
|
|
35
|
+
access, ask the user for approval to start authentication. Once approved, run
|
|
36
|
+
the appropriate command below and ask the user to complete NUS SSO in the
|
|
37
|
+
browser window:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
uv run canvas auth login
|
|
41
|
+
uv run talent-connect auth login
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Do not require authentication for NUSMods: its APIs are public, so use direct
|
|
45
|
+
requests or available browser skills as appropriate.
|
|
46
|
+
|
|
47
|
+
Prefer the repository's direct authenticated `api` command for endpoint
|
|
48
|
+
discovery and validation. It reuses the durable saved login and has lower cost
|
|
49
|
+
and overhead than a built-in browser/app connector. When page-level inspection
|
|
50
|
+
is necessary, use the repository's `playwright-cli` command; it injects that
|
|
51
|
+
same saved authentication into a named `@playwright/cli` session that later CLI
|
|
52
|
+
commands can reuse. Avoid built-in app/browser connectors for Canvas and
|
|
53
|
+
TalentConnect maintenance because their authentication is not persisted for
|
|
54
|
+
subsequent repository commands and they add unnecessary overhead.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
uv run canvas api /api/v1/users/self/profile
|
|
58
|
+
uv run canvas playwright-cli --session canvas
|
|
59
|
+
|
|
60
|
+
uv run talent-connect api /api/auth/
|
|
61
|
+
uv run talent-connect playwright-cli --session talent-connect
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The browser-opening commands leave their sessions running. Continue with, for
|
|
65
|
+
example, `playwright-cli -s=canvas snapshot`, and close a session explicitly
|
|
66
|
+
when the task is finished.
|
|
67
|
+
|
|
68
|
+
## Updating a remote integration
|
|
69
|
+
|
|
70
|
+
Remote interfaces change. When adding support for a new or updated Canvas or
|
|
71
|
+
TalentConnect page, field, endpoint, filter, or workflow:
|
|
72
|
+
|
|
73
|
+
1. Check auth status before beginning remote investigation.
|
|
74
|
+
2. Inspect the smallest useful read-only API call first with the app's `api`
|
|
75
|
+
command. Use the authenticated `playwright-cli` session for network, DOM, or
|
|
76
|
+
interaction details that the direct API cannot reveal.
|
|
77
|
+
3. Record the observed request/response contract and preserve existing unknown
|
|
78
|
+
fields unless there is a reason to normalize them.
|
|
79
|
+
4. Implement the narrowest package-local change, sharing only infrastructure
|
|
80
|
+
that truly applies to multiple apps.
|
|
81
|
+
5. Add or update deterministic unit tests, then run the focused tests and the
|
|
82
|
+
full unit suite.
|
|
83
|
+
6. Follow unit tests with safe real-service end-to-end checks when remote
|
|
84
|
+
behavior is relevant. Read-only checks such as auth status, profile fetches,
|
|
85
|
+
small list/detail requests, and page inspection are allowed and encouraged
|
|
86
|
+
by default unless the user says otherwise.
|
|
87
|
+
|
|
88
|
+
Real read-only API calls and actual use of the repository's `playwright-cli`
|
|
89
|
+
commands are allowed by default and are required for many remote-integration
|
|
90
|
+
tasks; mocks alone are not proof that a changed remote interface still works.
|
|
91
|
+
|
|
92
|
+
Any operation that would exercise real write access on the user's behalf needs
|
|
93
|
+
the user's explicit approval first. This includes creating, editing, deleting,
|
|
94
|
+
submitting, applying, bookmarking, messaging, enrolling, or otherwise changing
|
|
95
|
+
remote state. Approval for read-only investigation does not imply approval for
|
|
96
|
+
writes. Prefer a read-only status/detail request as the end-to-end smoke test
|
|
97
|
+
whenever it can validate the implementation safely.
|
sk4n-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- Initial public release.
|
|
6
|
+
- Provide Canvas, NUSMods, TalentConnect, and shared `sk4n` command-line tools.
|
|
7
|
+
- Bundle agent skills for the supported NUS services. Provide cli commands to skill management
|
|
8
|
+
|
|
9
|
+
[0.1.0]: https://github.com/hykzr/sk4n/releases/tag/v0.1.0
|