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
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,29 @@ All notable changes to `sustech-cli` are documented in this file.

## [Unreleased]

## [0.11.0] - 2026-09-07

### Added

- Added Blackboard content trees, rosters, message and discussion reads,
submitted-file downloads, cross-course assignment/grade summaries, and
guarded preview/apply commands for messages, discussion posts/replies and
file or text assignment submissions. Remote writes remain fixture-tested
and require an exact reviewed payload plus explicit confirmation.
- Added per-service authentication checks and ephemeral, manual Blackboard
browser authentication for read-only fallback workflows.

- Expanded the public NCES integration with exact course-code resolution,
teacher profiles, course rating statistics, filtered review pagination, and
typed MCP tools. NCES-generated summaries are explicitly labelled as
community AI summaries rather than official course information.
- Added `bb announcements` to aggregate visible system and course
announcements while preserving successful results and reporting inaccessible
courses as partial failures.
- Extended `online search` with a fixed-allowlist `manual` section covering
selected SUSTech Online service, study, transport, life, facility, and
calendar guidance with source, freshness, and CC BY-SA metadata.

- Added public `talks list` and `talks search` commands for official SUSTech
homepage lectures, showing upcoming events by default and all currently
displayed events with `--all`, with source metadata and text/JSON/JSONL output.
Expand All @@ -17,6 +38,14 @@ All notable changes to `sustech-cli` are documented in this file.

### Changed

- Daily context includes the latest visible Blackboard announcement while
retaining Shanghai timezone, empty/partial source states and public-source
failure handling.

- NCES browse sorting now uses the upstream server-side sort, and NCES search
supports typed course, teacher, and review result pages.
- The local MCP surface now exposes `42` typed public/local read-only tools.

- Made planning-oriented availability, enrollment, degree-progress, and
degree-missing JSON use documented minimum-data projections; grade-free
output is the default.
Expand All @@ -29,6 +58,10 @@ All notable changes to `sustech-cli` are documented in this file.

### Fixed

- Made the context outage regression deterministic with isolated offline
fixtures so ordinary CI no longer depends on the public calendar network.
- Invalid numeric HTML entities no longer crash text normalization.

- Corrected terminal-table alignment for Unicode Roman numerals, ellipses,
and combining characters, and kept grapheme clusters intact during truncation.
- Made `auth status` use a metadata-only macOS Keychain lookup instead of
Expand All @@ -39,6 +72,9 @@ All notable changes to `sustech-cli` are documented in this file.

### Security

- Browser-backed Blackboard reads validate every redirect before sending
cookies and enforce cookie expiration and path boundaries.

- Selection transport ambiguity now returns an explicit non-retriable outcome
with a local correlation ID, while raw upstream mutation and personal
selection envelopes are excluded from default CLI output.
Expand Down
65 changes: 56 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,18 @@ Public data does not require an account:
```bash
sustech calendar day 2026-09-01
sustech faculty search "computer vision"
sustech online search "校园卡" --section manual
sustech online manual list --source service --limit 10
sustech online manual get ID_OR_TITLE
sustech online talks list --limit 10
sustech talks list
sustech online contact search "教学"
sustech nces filter-options
sustech nces browse --offering-unit "计算机科学与工程系" --page-size 5
sustech nces global-stats
sustech nces rankings top-teachers --limit 5
sustech nces by-code CS302 --term 20252
sustech nces reviews 244 --sort newest --page-size 5
sustech transit lines
sustech library search "graph neural networks" --limit 5
```
Expand All @@ -60,6 +69,18 @@ sustech tis plan explain CS330 --round bxxk
sustech tis degree missing
sustech tis degree progress
sustech bb calendar --type GradebookColumn
sustech bb announcements --days 14
sustech bb deadlines --days 14 --submission-state not_attempted --json
sustech bb tree _8537_1 --max 50
sustech bb types --course MSE306
sustech bb roster _8537_1 --role Student --page-size 10
sustech bb discussions _5325_1 --page-size 10
sustech bb grades --course MSE306 --submission-state completed --limit 10 --json
sustech bb assignments --course MSE306 --with-attempts --json
sustech bb assignments _8537_1 --with-attempts --json
sustech bb assignments _8537_1 --submission-state not_attempted --json
sustech bb messages _8537_1 --folder-type Inbox --page-size 10
sustech bb attempt-files _8537_1 _2201_1
sustech tis schedule
sustech bb courses
```
Expand Down Expand Up @@ -115,8 +136,9 @@ For an agent without Skill support, provide this short instruction:

A Skill is the onboarding layer; the CLI remains the executable source of
truth. The package also ships a local `stdio` MCP entrypoint, `sustech-mcp`, for
clients that support native tools. It needs no hosted server and exposes `33`
typed public/local read-only tools plus JSON resources, resource templates, and
clients that support native tools. It needs no hosted server and exposes `42`
typed read-only tools in total (`39` public allowlisted tools plus `3` metadata
tools), plus JSON resources, resource templates, and
prompts for discovery, public campus data, library, faculty, transit, NCES,
papers, and selected SUSTech Online reads. Authenticated data, browser flows,
local writes, and remote mutations remain unavailable through MCP. See
Expand All @@ -134,9 +156,9 @@ version's exact command, authentication, network, and confirmation metadata.
| Diagnostics | version, capabilities, consequences, doctor | Local; optional live auth checks |
| Academic context | calendar, Context v2 live summaries, profile reports, academic snapshots, `academic changes`, one-shot `academic watch` | Public and authenticated reads; guarded local exports |
| TIS | catalog, schedule, grades, exams, TIS-reported degree progress, conservative missing-course report, persistent planning, `tis plan solve/explain/recommend`, local degree audit, live classrooms, iCalendar | CAS login; selection/enrollment writes are confirm-gated |
| Blackboard | courses, deadlines, calendar reads, native calendar-link workflow, search, attachment download/sync, attempts, submission | CAS login for REST reads; the native calendar link is a separate stored secret and local writes are guarded |
| Blackboard | courses, roster, course messages, message send preview/apply, discussions, recursive content trees, content type summaries, announcements, deadlines, calendar reads, cross-course grades, per-course and cross-course assignment/attempt overviews, native calendar-link workflow, search, attachment download/sync, attempts, submission | CAS login for REST reads; `bb roster`, `bb messages` / `bb message-participants`, `bb message-send preview/apply`, `bb discussion-groups`, announcement aggregation, `bb tree`, cross-course `bb grades`, cross-course `bb assignments --course ...`, `bb assignments --with-attempts` / `--submission-state`, `bb deadlines --submission-state`, and `bb types` preserve partial failures. Blackboard discussions use the official Learn REST discussion API when the target course exposes it; Original-course forum lists, `bb discussion` thread reads, and `bb discussion-replies` thread-detail reads fall back to the Blackboard HTML discussion board, while group reads and discussion writes that still require the REST surface fail closed with `BLACKBOARD_DISCUSSIONS_UNSUPPORTED`. The native calendar link is a separate stored secret, and local writes are guarded |
| Library and campus services | Primo catalog search/detail, WS programs, eHall booking, library booking, PMS jobs and usage | Public catalog reads plus authenticated reads; booking and queue writes are confirm-gated |
| Research and courses | Crossref/OA papers, NCES browse and search, SUSTech Online talks | Public; OA downloads use guarded local paths; NCES and SUSTech Online remain community references only |
| Research and courses | Crossref/OA papers, NCES browse/filter-options/global-stats/rankings/search/by-code/course/reviews/teacher/stats, SUSTech Online talks and selected handbook search | Public; OA downloads use guarded local paths; NCES and SUSTech Online remain community references only |
| Campus and device context | faculty, resources, transit, Wi-Fi status/events | Public or local |
| Community directory | Selected institutional SUSTech Online contacts with provenance and freshness advisories | Public community source; emergency, financial, personal, dining/chat, and professor-list sections are excluded |

Expand Down Expand Up @@ -215,7 +237,7 @@ review. A successful envelope looks like this:
"ok": true,
"command": "version",
"data": {
"version": "0.10.0",
"version": "0.11.0",
"runtime": "node v22.19.0"
}
}
Expand Down Expand Up @@ -249,6 +271,8 @@ password. Credential-helper commands are bounded to five seconds and report
```bash
sustech auth login --profile main
sustech auth check --profile main --service bb --json
sustech auth check --service bb --browser --interactive --json
sustech doctor --service bb --live --browser --interactive --json
sustech auth logout --profile main
```

Expand All @@ -257,6 +281,11 @@ the documented environment variables or credentials file. Service sessions and
cookies remain in memory. See [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md)
for precedence, backend requirements, and non-interactive use.

For Blackboard only, `auth check` and `doctor --live` also support a read-only
browser-backed verification path with `--browser`, plus `--interactive` when
the user needs to finish CAS manually. That path never accepts browser
credentials in the CLI and never persists browser cookies.

Blackboard also exposes a private native calendar subscription link. Treat that
link like a bearer token or password: store it only through stdin, let `show`
mask it by default, and reveal it only with an explicit `--reveal`:
Expand Down Expand Up @@ -308,8 +337,14 @@ Blackboard attachment and submission example:

```bash
sustech bb attachments _8537_1 _629896_1 --json
sustech bb grades --course CS208 --submission-state completed --limit 10 --json
sustech bb assignments --course CS208 --with-attempts --json
sustech bb assignments _8537_1 --with-attempts --json
sustech bb download _8537_1 _629896_1 ATTACHMENT_ID \
--destination ./homework.pdf
sustech bb attempt-files _8537_1 _2201_1 --json
sustech bb attempt-download _8537_1 _2201_1 FILE_ID \
--destination ./submitted-homework.pdf

sustech bb submit preview \
--course-id _8537_1 --content-id _629896_1 --file homework.pdf
Expand Down Expand Up @@ -356,7 +391,7 @@ sustech context --live --level verbose
`context` now has three explicit detail levels:

- `terse`: date, teaching week and parity, holiday/makeup timetable, and current/next class; only the timetable is requested with `--live`
- `normal` (default): adds the next assignment deadline, evaluation, exam, weather and AQI with `--live`
- `normal` (default): adds the next assignment deadline, recent Blackboard announcement, evaluation, exam, weather and AQI with `--live`
- `verbose`: also retrieves library opening status

All dates and display times use **Asia/Shanghai**, including on overseas machines.
Expand Down Expand Up @@ -420,6 +455,12 @@ review instead of being promoted to a definite requirement match.

- Blackboard submission follows official Learn REST attempt/upload endpoints
and is fixture-tested, but it has not yet performed a real Blackboard write.
- 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
Blackboard exposes a working attempt-file download endpoint for that record;
otherwise the CLI now fails closed with
`BLACKBOARD_ATTEMPT_FILE_UNAVAILABLE`.
- Primo catalog access has both direct and browser-backed paths, but direct
public HTTP access can still depend on the local runtime's TLS behavior. When
in doubt, use `--browser` and complete any CAS step manually.
Expand All @@ -428,9 +469,15 @@ 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.
- The supported submission surface is Classic/Original assignment attempts;
the CLI does not scrape or silently fall back to the legacy
`uploadAssignment` HTML form.
- 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 `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
is still protocol/fixture-tested only.
- Newly added TIS selection, booking, library-booking, and PMS write paths are
protocol/fixture-tested only. No real account mutation was performed while
building this expansion.
Expand Down
14 changes: 11 additions & 3 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,22 @@ commands for them.
and one-shot `academic watch` do not mutate remote campus state.
- `bb submit preview` authenticates for live read-only preflight checks but
never calls a mutation endpoint.
- `bb discussions`, `bb discussion`, and `bb discussion-replies` prefer the
official Learn REST discussion endpoints with explicit `offset`/`limit`
paging and server-side title, gradable, author, status, and read-state
filters; for Blackboard Original courses that reject REST, forum, thread,
and thread-detail reply reads fall back to the HTML discussion board, while
group reads and discussion writes remain REST-only and fail closed.
- `bb calendar` is an authenticated read with optional date, type, and course
filters. `bb calendar-link set` validates a native Learn ICS feed and stores
it as a separate operating-system secret; `show` masks it by default, and
`fetch` can refresh the feed without a fresh CAS login.
- `bb attachments` keeps teacher-provided content files separate from student
attempt files. `bb download` is a local mutation with an explicit destination,
same-origin URL checks, exclusive no-overwrite placement, and a portable
filesystem fallback when hard links are unavailable.
attempt files. `bb download` and `bb attempt-download` are local mutations
with explicit destinations, same-origin URL checks, exclusive no-overwrite
placement, and a portable filesystem fallback when hard links are
unavailable. `bb attempt-files` exposes the student's submitted filenames
without mixing them into the teacher-attachment surface.
- Booking, library-booking, and PMS sessions keep credentials and session
material in memory only, reject requests outside their allowlists, and never
expose a generic authenticated write primitive.
Expand Down
8 changes: 8 additions & 0 deletions docs/AUTHENTICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ submission state remain in memory.
sustech auth login
sustech auth status
sustech auth check --service bb
sustech auth check --service bb --browser --interactive
sustech doctor --service bb --live --browser --interactive
sustech auth logout
```

Expand All @@ -34,6 +36,12 @@ CAPTCHA, the CLI stops before password submission and returns
`CAS_INTERACTIVE_CHALLENGE_REQUIRED`. It does not attempt to bypass that
challenge.

For Blackboard only, `auth check` and `doctor --live` also support a separate
read-only browser-backed verification path. Use `--browser` to request that
path, and add `--interactive` when you need to complete the CAS page manually
in the opened browser window. This path does not accept browser credentials in
the CLI and does not persist browser cookies.

## Primo browser mode

The library catalog browser flow is separate from `auth login`:
Expand Down
48 changes: 47 additions & 1 deletion docs/MCP.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ The entrypoint behavior is intentionally narrow:

## Tool surface

The server exposes `33` typed public/local read-only tools. It does not expose
The server exposes `42` typed read-only tools in total (`39` public allowlisted
tools plus `3` metadata tools). It does not expose
a generic string runner such as `sustech_run`.

Core metadata:
Expand All @@ -66,12 +67,38 @@ Public research and catalog data:

- `sustech_papers_search`
- `sustech_nces_browse`
- `sustech_nces_filter_options`
- `sustech_nces_global_stats`
- `sustech_nces_rankings`
- `sustech_nces_search`
- `sustech_nces_by_code`
- `sustech_nces_course`
- `sustech_nces_reviews`
- `sustech_nces_teacher`
- `sustech_nces_stats`
- `sustech_library_search`
- `sustech_library_detail`
- `sustech_library_search_url`

`sustech_nces_browse` accepts an optional `offeringUnit` string that maps to
NCES `offering_unit`, and `sustech_nces_filter_options` returns the live
accepted values from NCES.

`sustech_nces_search` accepts `type=all|course|teacher|review`. Its top-level
`items`, `total`, `pages`, `page`, and `perPage` always describe the selected
bucket (`course` when `type=all`). For `type=all`, the response also exposes
`aggregateTotal` as the sum of the current course, teacher, and review bucket
totals, plus `aggregateItems` and `aggregateShown` for the currently returned
mixed page. It keeps explicit per-bucket totals and page counts, plus
`courseItems`, `selectedBucket`, and `selectedItems` so MCP callers can render
the compatibility bucket directly while still inspecting the mixed counts
without pretending they share one real combined pagination stream.

`sustech_nces_course` and `sustech_nces_by_code` return the current review
window by default. `sustech_nces_by_code` also accepts repeated `teacher`
filters for section disambiguation. Pass `allReviews: true` only when you
explicitly want the tool to fetch every currently exposed review page.

Public faculty and campus datasets:

- `sustech_faculty_departments`
Expand All @@ -92,9 +119,28 @@ Public SUSTech Online layer:
- `sustech_online_talks_list`
- `sustech_online_talks_search`
- `sustech_online_talks_get`
- `sustech_online_manual_list`
- `sustech_online_manual_get`
- `sustech_online_contact_search`
- `sustech_online_contact_get`

`sustech_online_search` accepts `section: "manual"` for the selected handbook
corpus. Each returned hit preserves community authority, source path, license,
fetch/update metadata, and freshness advisories. The `since` and `until` fields
are available only when the section is omitted or set to `"talks"`; the typed
schema excludes them for `"contact"` and `"manual"`. The manual branch also
accepts optional allowlisted `source` filters from
`service|study|transport|life|facility|calendar`, and returns
`manualMatchedTotal` when the section is `"manual"` so callers can distinguish
returned hits from the full pre-limit manual match count.

`sustech_online_manual_list` accepts repeated allowlisted `source` filters from
`service|study|transport|life|facility|calendar`, and
`sustech_online_manual_get` accepts the deterministic handbook id returned by
list or search, or an exact handbook title. `sustech_online_manual_list` also
returns `matchedTotal` so callers can distinguish the allowlisted corpus size
from the current limited result count.

All tools return the same versioned JSON envelope that the direct CLI already
uses, both as `structuredContent` and as a text fallback. This keeps the CLI as
the installed source of truth while giving MCP clients typed input schemas.
Expand Down
Loading