Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ All notable changes to `sustech-cli` are documented in this file.

## [Unreleased]

## [0.11.1] - 2026-09-12

### Fixed

- Submit Classic/Original Blackboard assignments with a fresh, target-validated
HTTP form and one multipart POST using the CAS session. Retain reviewed hashes,
confirmation and new-attempt read-back; no Playwright or public REST upload
authorization is required. Text/comments use the form's exposed editor fields.
- Handle an initial attempts-list 404 as empty only after verifying the exact
accessible assignment and its blank first-submission view form. Other errors
and later-page failures remain errors.
- Preserve submission failure stage and sanitized upstream status/path. Never
automatically replay a submission POST, including across HTTP redirects.
- Use a portable file URL for the offline submission fixture on Windows.

### Validation

- An authorized Original file resubmission passed live CLI submission and REST
read-back on 2026-09-11. Text submission and first-submission 404 recovery remain
covered by isolated HTTP fixtures.

## [0.11.0] - 2026-09-07

### Added
Expand Down
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ review. A successful envelope looks like this:
"ok": true,
"command": "version",
"data": {
"version": "0.11.0",
"version": "0.11.1",
"runtime": "node v22.19.0"
}
}
Expand Down Expand Up @@ -453,8 +453,10 @@ review instead of being promoted to a definite requirement match.

## Current limitations

- Blackboard submission follows official Learn REST attempt/upload endpoints
and is fixture-tested, but it has not yet performed a real Blackboard write.
- Blackboard submission uses a Classic/Original HTTP form with the CAS session
and REST attempt read-back. An individual Original file resubmission passed
live CLI submission and read-back on 2026-09-11. Text submission and the
first-submission 404 fallback remain fixture-tested only.
- Student-submitted attempt files are separate from teacher-provided content
attachments. `bb attempt-files` lists one attempt's files, and
`bb attempt-download` downloads one of them to an explicit local path when
Expand All @@ -469,11 +471,12 @@ review instead of being promoted to a definite requirement match.
an interactive slide CAPTCHA. The CLI will not bypass that challenge. A
previously stored Blackboard native calendar link can still be fetched
without CAS.
- Blackboard submission stays on the official Learn REST path: file attachments
remain limited to Classic/Original assignment attempts, and supported
assignment targets can also submit text through the attempt payload. The CLI
does not scrape or silently fall back to the legacy `uploadAssignment` HTML
form.
- Blackboard submission remains entirely in the CLI: a fresh form nonce and
exact target are validated before one multipart POST to `uploadAssignment`.
It supports individual Classic/Original file or text submissions with no
Playwright dependency in the write path. Ultra/group assignments and silent
draft resumption are unsupported. An attempts-list 404 becomes empty only
after a matching blank first-submission view form confirms that state.
- Blackboard `bb message-send preview/apply` stays on the official course
message create endpoint, binds apply to the previewed SHA-256 plus exact
recipient IDs, and verifies the created message by Sent-folder read-back. It
Expand Down
8 changes: 7 additions & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,13 @@ commands for them.
- Remote mutations cover TIS enroll/cart/drop/bid, Blackboard submission,
eHall and library booking create/cancel, and PMS queue upload/delete. Every
path requires `--confirm`; file-bound uploads additionally require the
previewed SHA-256. These paths are protocol-fixture-tested, not live-written.
previewed SHA-256. These paths have protocol-fixture coverage. An authorized
individual Blackboard Original file resubmission additionally passed live
submission and REST read-back on 2026-09-11.
- Blackboard Original submission reads a fresh assignment form with CAS cookies
and sends one multipart HTTP POST. Nonces stay in memory; redirects cannot
replay the POST. REST read-back must identify one new submitted attempt and
verify its file/text and optional comment before reporting success.
- eHall booking and library-booking create previews attempt exact slot
availability checks first and fail closed when the live evidence is missing,
malformed, or ambiguous.
Expand Down
8 changes: 5 additions & 3 deletions docs/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ Ports are fixture-driven and land in this standalone repository. Opt-in,
read-only live smoke tests on 2026-08-26 covered TIS enrollment reads,
Blackboard courses, WS programs, eHall rooms, and library-booking identity,
summary, lab, and reservation-count reads. PMS remained blocked by its
campus-network gate. All newly added mutation paths remain fixture-tested only;
no real account mutation was attempted while completing this expansion.
campus-network gate. That expansion did not perform real account mutations.
A later authorized individual Blackboard Original file resubmission passed live
CLI submission and REST read-back on 2026-09-11; other mutation paths remain
fixture-tested only.

| Area | Read operations | Mutations | Status | Priority |
| --- | --- | --- | --- | --- |
Expand All @@ -25,7 +27,7 @@ no real account mutation was attempted while completing this expansion.
| Academic snapshots | normalized TIS state with optional Blackboard deadlines; `academic changes`; one-shot `academic watch` | guarded versioned snapshot files | Implemented with digest verification, no-overwrite defaults, and no remote write behavior | P1 |
| Resources | built-in campus resource registry and search | none | Implemented | P1 |
| Wi-Fi | current association and recent macOS SUSTC Wi-Fi events | none | Implemented on macOS only | P1 |
| Blackboard | courses, content, roster, course messages, course-message send preview/apply, discussions, teacher-provided attachment listing/download, per-course and cross-course assignments, cross-course grades, deadlines, calendar REST reads, search, attempts, native calendar-link storage/fetch | guarded local sync, optional ICS write, Classic/Original file submission plus supported text submission | CLI CAS login and courses read live-smoked; roster, course-message, discussion-group discovery, and course-message send now follow official current Learn REST endpoints. Message send validates exact roster recipients, binds apply to the previewed text SHA-256, and verifies the created Sent-folder record. Calendar reads, native feed-link storage/fetch, local download/sync, and the hash-bound submission workflow use official Learn REST/BBML paths or keyring fixtures and remain conservatively documented | P2 |
| Blackboard | courses, content, roster, course messages, course-message send preview/apply, discussions, teacher-provided attachment listing/download, per-course and cross-course assignments, cross-course grades, deadlines, calendar REST reads, search, attempts, native calendar-link storage/fetch | guarded local sync, optional ICS write, individual Classic/Original file and text submission | CLI CAS login and courses read live-smoked; roster, course-message, discussion-group discovery, and course-message send now follow official current Learn REST endpoints. Message send validates exact roster recipients, binds apply to the previewed text SHA-256, and verifies the created Sent-folder record. Calendar reads, native feed-link storage/fetch and local download/sync use Learn REST/BBML paths or keyring fixtures. Assignment submission uses a fresh Classic/Original HTTP form with CAS cookies, hash binding and REST read-back; individual Original file resubmission passed a live check on 2026-09-11, while text remains fixture-tested | P2 |
| Library catalog | Primo search/detail reads, browser fallback transport | none | Implemented with direct public HTTP plus manual `--browser [--interactive]` fallback; browser auth stays user-completed and cookies are not persisted by the CLI | P2 |
| Library booking | account state, idle summary, labs, rooms, reservation counts, reservations | guarded create/cancel | Login, account, summary, labs, and count live-smoked; previews now use conservative exact-availability checks and fail closed when the slot cannot be proved safe | P2 |
| E-Hall booking | redacted user profile, rooms, meetings | guarded create/cancel | Login and rooms read live-smoked; previews now use conservative exact day/time availability checks and fail closed on unreadable overlap state | P2 |
Expand Down
6 changes: 6 additions & 0 deletions docs/OUTPUT.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,9 @@ names rather than raw download URLs. A successful `bb attempt-download` result
contains the selected file identity, the absolute destination path, byte count,
content type, and SHA-256. The `files` read-back inside a successful
`bb submit apply` result uses the same URL-free file identity shape.

Blackboard submission preparation failures report `submissionPostSent: false`.
After a POST starts, an unverified result returns
`BLACKBOARD_SUBMISSION_OUTCOME_UNKNOWN` with exit code 5. Diagnostics retain the
stage and available upstream status/path, excluding form nonces, response bodies,
and credential-bearing URL queries.
33 changes: 23 additions & 10 deletions docs/SERVICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ while the CLI already supplies that transport for a specific command family.

| Service | Availability | Auth | CLI surface today | Notes |
| --- | --- | --- | --- | --- |
| `blackboard` | `adapter_required` | CAS cookie session | `bb user`, `bb courses`, `bb content`, `bb tree`, `bb types`, `bb attachments`, `bb download`, `bb roster`, `bb message-folders`, `bb messages`, `bb message-participants`, `bb message-send preview/apply`, `bb discussions`, `bb discussion-groups`, `bb discussion`, `bb discussion-replies`, `bb assignments`, `bb grades`, `bb attempt-files`, `bb attempt-download`, `bb announcements`, `bb deadlines`, `bb calendar`, `bb search`, `bb sync`, `bb attempts`, `bb submit preview`, `bb submit apply`, `bb calendar-link set/show/fetch/delete` | CLI CAS login and announcement aggregation passed opt-in read-only live smoke tests. Recursive content-tree reads via `bb tree`; course roster reads via `bb roster`; course-message reads via `bb message-folders` / `bb messages` / `bb message-participants`; and discussion/forum reads via `bb discussions` / `bb discussion-groups` / `bb discussion` / `bb discussion-replies` when Blackboard exposes a compatible Learn REST discussion surface. For Blackboard Original courses that reject the REST discussion API, `bb discussions` falls back to the HTML discussion-board forum list, `bb discussion` falls back to the HTML thread list, and `bb discussion-replies` falls back to the HTML thread-detail reply list, while group reads and discussion writes that still require the REST surface fail closed with `BLACKBOARD_DISCUSSIONS_UNSUPPORTED`. `bb message-send preview/apply` uses the official Learn REST course-message create endpoint, validates exact recipient IDs against the live course roster, binds apply to the reviewed text SHA-256, and verifies the created message by Sent-folder read-back. Cross-course `bb grades`, cross-course `bb assignments --course ...`, `bb assignments --with-attempts`, `bb assignments --submission-state ...`, `bb deadlines --submission-state ...`, and `bb types` preserve accessible results and record per-course, per-folder, or per-assignment failures as partial output where applicable. Content download/sync supports the official Original endpoint and embedded BBML links. Attempt-file reads expose the authenticated student's submitted files separately from teacher attachments; attempt-file downloads work when Blackboard exposes a usable download endpoint for that record and otherwise fail closed as unavailable. Blackboard message-send and assignment submission remain fixture-tested only: file attachments still follow the Classic/Original attempt-file path, while supported Blackboard assignment targets can also submit text through the official attempt payload. |
| `blackboard` | `adapter_required` | CAS cookie session | `bb user`, `bb courses`, `bb content`, `bb tree`, `bb types`, `bb attachments`, `bb download`, `bb roster`, `bb message-folders`, `bb messages`, `bb message-participants`, `bb message-send preview/apply`, `bb discussions`, `bb discussion-groups`, `bb discussion`, `bb discussion-replies`, `bb assignments`, `bb grades`, `bb attempt-files`, `bb attempt-download`, `bb announcements`, `bb deadlines`, `bb calendar`, `bb search`, `bb sync`, `bb attempts`, `bb submit preview`, `bb submit apply`, `bb calendar-link set/show/fetch/delete` | CLI CAS login and announcement aggregation passed opt-in read-only live smoke tests. Recursive content-tree reads via `bb tree`; course roster reads via `bb roster`; course-message reads via `bb message-folders` / `bb messages` / `bb message-participants`; and discussion/forum reads via `bb discussions` / `bb discussion-groups` / `bb discussion` / `bb discussion-replies` when Blackboard exposes a compatible Learn REST discussion surface. For Blackboard Original courses that reject the REST discussion API, `bb discussions` falls back to the HTML discussion-board forum list, `bb discussion` falls back to the HTML thread list, and `bb discussion-replies` falls back to the HTML thread-detail reply list, while group reads and discussion writes that still require the REST surface fail closed with `BLACKBOARD_DISCUSSIONS_UNSUPPORTED`. `bb message-send preview/apply` uses the official Learn REST course-message create endpoint, validates exact recipient IDs against the live course roster, binds apply to the reviewed text SHA-256, and verifies the created message by Sent-folder read-back. Cross-course `bb grades`, cross-course `bb assignments --course ...`, `bb assignments --with-attempts`, `bb assignments --submission-state ...`, `bb deadlines --submission-state ...`, and `bb types` preserve accessible results and record per-course, per-folder, or per-assignment failures as partial output where applicable. Content download/sync supports the official Original endpoint and embedded BBML links. Attempt-file reads expose the authenticated student's submitted files separately from teacher attachments; attempt-file downloads work when Blackboard exposes a usable download endpoint for that record and otherwise fail closed as unavailable. Blackboard message-send and assignment text submission remain fixture-tested only; individual Original file resubmission passed live CLI submission and REST read-back on 2026-09-11. Individual Classic/Original assignment files and text use a fresh HTTP form with the CAS session and REST read-back; Ultra/group submission is unsupported. |
| `booking` | `implemented` | CAS cookie session plus booking bearer token, campus reachability | `booking whoami`, `booking rooms`, `booking my-meetings`, `booking create preview/apply`, `booking cancel preview/apply` | CLI login and room-list read passed an opt-in live smoke test on 2026-08-26. Create preview now checks the live room calendar for the exact day/time and fails closed when overlaps or unreadable calendar state prevent a safe decision. Remote writes still require preview, `--confirm`, and exact read-back. |
| `library-catalog` | `implemented` | public HTTP or manual browser session | `library search`, `library detail` | Primo public search/detail normalization is implemented, and `--browser [--interactive]` provides a manual browser-backed fallback. The CLI never fabricates records, never accepts browser credentials, never solves CAPTCHAs, and never persists browser cookies. Some runtimes may still need the browser path because upstream TLS behavior can differ by host. |
| `library-booking` | `implemented` | IC booking cookie session, campus reachability | `lib-booking whoami`, `lib-booking home-summary`, `lib-booking labs`, `lib-booking rooms`, `lib-booking reservation-count`, `lib-booking reservations`, `lib-booking create preview/apply`, `lib-booking cancel preview/apply` | Login plus identity, summary, labs, and count reads passed an opt-in live smoke test on 2026-08-26. Create preview now combines room open-times with reservation metadata and fails closed when exact availability cannot be proved safely. Membership and capacity rules remain conservative. |
Expand Down Expand Up @@ -126,18 +126,31 @@ defaults as `bb download`. If Blackboard exposes only metadata and the
official download endpoint still returns `404`, the CLI reports
`BLACKBOARD_ATTEMPT_FILE_UNAVAILABLE` instead of a generic transport error.

Blackboard assignment submission uses the official Learn REST APIs: v2 grade
columns and attempts, v1 temporary uploads, and v1 attempt files. Text
submissions can use the official attempt payload on supported assignment
targets. The attempt-file endpoint is still limited by Blackboard to
Classic/Original assignments, which the read-only preflight verifies from both
the content handler and grade-column metadata.
Blackboard assignment submission uses the Classic/Original HTTP form with the
existing CAS cookie session. The CLI reads a fresh form during apply, validates
its target and nonce, and sends one multipart POST to `uploadAssignment`.
No Playwright is involved in this submission path. File and plain-text submissions
are supported; text/comments require the corresponding form editor fields.
Ultra and group assignments are not supported by this form workflow.

Attempt discovery and read-back use Learn REST. An initial attempts-list `404`
is treated as an empty history only when the exact accessible Classic assignment's
read-only `mode=view` page exposes a matching blank first-submission form.
An inaccessible/ambiguous page, existing draft/history, or later-page failure
remains an error. Preview never requests `action=newAttempt` or sends a POST.

`bb submit preview` authenticates but only reads. `bb submit apply` requires
`--confirm`, the previewed `--expected-sha256`, a fresh preflight, and a
post-submit read-back of both attempt status and filename. Existing in-progress
attempts are not silently resumed. An uncertain write returns exit code 5 with
`DO_NOT_RETRY_AUTOMATICALLY`; the CLI never falls back to the legacy HTML form.
post-submit read-back of a single new attempt's status and filename or text,
plus comments when supplied. Existing in-progress attempts and drafts are not
silently resumed. An uncertain write returns exit code 5 with
`DO_NOT_RETRY_AUTOMATICALLY`; the CLI does not retry or redirect-replay a POST.
Error diagnostics retain the stage and sanitized upstream status/path without
form nonces or response bodies. On 2026-09-11, an explicitly authorized
individual Original file resubmission passed live CLI submission and REST
read-back: a new NeedsGrading attempt, the expected filename, and a matching
receipt byte count were observed. Text submission and the first-submission
404 fallback remain covered by isolated HTTP fixtures only.

## TIS degree surfaces

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sustech-cli",
"version": "0.11.0",
"version": "0.11.1",
"description": "Human-friendly and agent-ready command-line access to SUSTech services.",
"license": "PolyForm-Noncommercial-1.0.0",
"type": "module",
Expand Down
Loading