Skip to content

Latest commit

 

History

History
181 lines (162 loc) · 9.88 KB

File metadata and controls

181 lines (162 loc) · 9.88 KB

Architecture

The CLI is organized around one rule: service logic returns typed values and never prints. Commands turn those values into a CommandResult; the output layer renders text, JSON, or JSONL.

command parser
    ↓
command handler       validates intent and confirmation
    ↓
service client        authentication, HTTP, pagination, normalization
    ↓
typed domain result
    ↓
output renderer       text | versioned JSON | streaming JSONL

Boundaries

  • src/cli.ts owns command routing, option validation, and user-facing help.
  • src/core owns credentials, errors, output contracts, capabilities, consequences, and other shared primitives.
  • src/core/keyring.ts keeps long-lived secrets behind platform adapters: macOS Keychain, Windows Credential Manager, Linux Secret Service, or (when Secret Service is unavailable) an encrypted local file store. CAS passwords and Blackboard native calendar links use separate secret namespaces. The local config contains profile metadata only for CAS credentials; the Blackboard calendar link does not create on-disk metadata.
  • src/sso owns generic CAS session flow. TIS, Blackboard, and WS reuse this layer instead of reimplementing login logic separately.
  • src/tis owns TIS protocol details, normalized course models, persistent planning, TIS-reported degree-progress normalization, conservative derived missing-course classification, local degree audit, live classroom/context helpers, multi-source ICS export, read-only plan explain/recommend enrichment, and guarded enroll/cart/drop/bid write paths.
  • src/calendar, src/faculty, src/online, src/transit, src/resources, and src/wifi own public or local-only data sources. src/online uses exact path allowlists and retains community provenance, freshness, and license metadata instead of presenting the source as official.
  • src/context composes a truthful snapshot from whichever sources are available, exposes Context v2 level/live enrichments, and marks missing or partial inputs explicitly.
  • src/profile aggregates only whitelisted student fields and can save a versioned, private local report without exposing raw upstream profiles.
  • src/academic and shared local-store helpers provide guarded, digest-verifiable local persistence, offline diffing, and the one-shot watch/update workflow.
  • src/services owns reusable campus-service adapters such as Blackboard, WS, booking, library booking, PMS, NCES, and papers, plus the authenticated session wrappers that sit in front of some of them.
  • src/services/library.ts owns direct Primo search/detail normalization, and src/services/library-browser.ts owns the browser-backed manual-auth Primo transport.
  • src/services/blackboard-calendar.ts owns native Learn ICS-link validation, masking, safe same-origin fetch, and bounded ICS parsing for the stored Blackboard calendar subscription workflow.
  • src/core/capabilities.ts is the machine-discoverable safety registry.
  • src/mcp exposes a local stdio MCP adapter over that registry. It uses a typed tool allowlist plus JSON resources and prompts, launches the packaged CLI without a shell, propagates MCP cancellation to the child CLI process, and rejects authenticated personal data, remote mutations, browser-assisted flows, local private state, and known local state writes.
  • Services must not write to stdout or stderr.
  • Machine-readable output is versioned by schemaVersion.
  • Text is the default; agents opt into --json or --jsonl explicitly.

Service layers

The repo now has three service-facing patterns:

  1. Direct clients

    Modules such as TIS, transit, calendar, papers, and NCES can create or own their HTTP access directly because they are either public or use the repo's built-in authentication flow.

  2. Adapter-first clients

    Modules in src/services accept a ServiceAdapter with a fetch(...) method. This keeps parsers and endpoint knowledge reusable across:

    • the CLI
    • future Web UI packages
    • tests with fixture-backed adapters
    • browser-backed or cookie-injected transports
  3. Authenticated wrappers

    Booking, library-booking, PMS, and the CLI's CAS-backed Blackboard/WS entrypoints now have repo-owned login wrappers that:

    • retrieve credentials just in time and keep cookies and transient tokens in memory only
    • constrain service origins; booking, library-booking, and PMS additionally enforce documented read allowlists and typed write endpoint allowlists
    • normalize the resulting responses through the same typed service layer

sustech services status reports the reusable service layer, not only whether a command exists. That is why booking, library-booking, and PMS now show implemented, while Blackboard and WS still show adapter_required at the service-module level even though the CLI already provides CAS-backed read commands for them.

Safety model

  • Read commands never mutate remote state.
  • Local planning commands such as tis enroll preview, tis selection preview, tis bid plan, tis plan explain, tis plan recommend, academic changes, 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 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.
  • library search and library detail support a direct public HTTP path plus --browser fallback. If the browser path reaches CAS, the user must finish that step manually. The CLI does not accept browser credentials, does not solve CAPTCHAs, and does not persist browser cookies.
  • auth login verifies the selected service before storing a password in the operating-system credential store. When Linux Secret Service is unavailable, the CLI falls back to an encrypted local file store (AES-256-GCM) that requires a master password. It never falls back to plaintext storage or session-only kernel keyrings.
  • If CAS responds with an interactive slide CAPTCHA, the shared login layer returns CAS_INTERACTIVE_CHALLENGE_REQUIRED before password submission instead of trying to bypass the challenge.
  • 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 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.
  • Local file mutations such as Blackboard download/sync, OA PDF fetch, iCalendar/profile/snapshot export, and plan persistence require explicit or well-scoped destinations, reject symbolic-link traversal, default to no-overwrite, and request mode 0600 for personal academic artifacts on POSIX platforms. Windows uses the destination filesystem's ACLs rather than POSIX mode bits.
  • Mutation commands use explicit preview/build phases and post-action verification. Any ambiguous remote result returns exit code 5 plus DO_NOT_RETRY_AUTOMATICALLY when write state cannot be determined safely.
  • TIS selection previews carry a local correlation ID but never claim upstream idempotency. Transport ambiguity is reconciled through bounded exact {courseId, rwh, round} reads rather than by repeating a mutation.
  • Planning-facing TIS output passes through field-allowlisted projections; broad upstream rows and raw mutation responses remain outside CLI JSON.
  • Consequence metadata lives in src/core/consequences.ts so agents can inspect risks and follow-up checks without scraping prose.
  • New authenticated campus-service wrappers are validated with protocol fixtures and transport guards. Opt-in read-only live smoke tests passed for booking and library-booking on 2026-08-26; PMS remained blocked by its campus-network gate.

Current shape

As the rewrite grows, command routing will likely split out of src/cli.ts, but the core rule stays the same: domain modules return typed values, renderers format them, and the CLI layer is where auth, confirmation, and output mode selection come together.