@priyadarship4/coursy 0.0.0-stage → 1.0.0

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.
Files changed (106) hide show
  1. package/README.md +210 -2
  2. package/bin/coursy.mjs +1432 -0
  3. package/client/dist/assets/index-Do3gCYxi.css +1 -0
  4. package/client/dist/assets/index-DxuZ2Pwp.js +69 -0
  5. package/client/dist/index.html +13 -0
  6. package/docs/BEST_PRACTICES.md +382 -0
  7. package/docs/DEPENDENCIES_AND_PLATFORM_LLD.md +219 -0
  8. package/docs/ENRICHMENT_MERGE_LLD.md +546 -0
  9. package/docs/LEARNING_ENGINE_LLD.md +161 -0
  10. package/docs/OPENCODE_GO_LLD.md +214 -0
  11. package/docs/PROJECT_STRUCTURE.md +193 -0
  12. package/docs/TEXT_COURSE_LLD.md +190 -0
  13. package/docs/WEBSITE_LLD.md +477 -0
  14. package/package.json +51 -4
  15. package/server/dist/cli-data.js +336 -0
  16. package/server/dist/config.js +89 -0
  17. package/server/dist/db/db.js +79 -0
  18. package/server/dist/features/courses/course.service.js +235 -0
  19. package/server/dist/features/courses/courses.controller.js +137 -0
  20. package/server/dist/features/courses/courses.repository.js +77 -0
  21. package/server/dist/features/courses/scan.service.js +164 -0
  22. package/server/dist/features/courses/section.repository.js +39 -0
  23. package/server/dist/features/enrichment/enrichment.config.js +119 -0
  24. package/server/dist/features/enrichment/enrichment.controller.js +642 -0
  25. package/server/dist/features/enrichment/enrichment.repository.js +289 -0
  26. package/server/dist/features/enrichment/enrichment.service.js +1038 -0
  27. package/server/dist/features/enrichment/events.service.js +55 -0
  28. package/server/dist/features/enrichment/pipeline/align.js +23 -0
  29. package/server/dist/features/enrichment/pipeline/concepts.js +72 -0
  30. package/server/dist/features/enrichment/pipeline/concepts.test.js +64 -0
  31. package/server/dist/features/enrichment/pipeline/export.js +29 -0
  32. package/server/dist/features/enrichment/pipeline/extract.js +104 -0
  33. package/server/dist/features/enrichment/pipeline/interview.js +82 -0
  34. package/server/dist/features/enrichment/pipeline/plan.js +109 -0
  35. package/server/dist/features/enrichment/pipeline/practice.js +107 -0
  36. package/server/dist/features/enrichment/pipeline/rollup.js +46 -0
  37. package/server/dist/features/enrichment/pipeline/summarize.js +70 -0
  38. package/server/dist/features/enrichment/pipeline/transcribe.js +64 -0
  39. package/server/dist/features/enrichment/prompts/templates.js +54 -0
  40. package/server/dist/features/enrichment/providers/llm.js +160 -0
  41. package/server/dist/features/enrichment/providers/llm.test.js +83 -0
  42. package/server/dist/features/enrichment/providers/media/subproc.js +48 -0
  43. package/server/dist/features/enrichment/providers/transcriber/fluidaudio.js +55 -0
  44. package/server/dist/features/enrichment/providers/transcriber/subtitle.js +51 -0
  45. package/server/dist/features/enrichment/providers/transcriber/types.js +9 -0
  46. package/server/dist/features/enrichment/providers/transcriber/whisper-api.js +29 -0
  47. package/server/dist/features/fs/fs.controller.js +36 -0
  48. package/server/dist/features/fs/fs.service.js +74 -0
  49. package/server/dist/features/learning/concept-materializer.js +104 -0
  50. package/server/dist/features/learning/engines/mastery.js +27 -0
  51. package/server/dist/features/learning/engines/mastery.test.js +39 -0
  52. package/server/dist/features/learning/engines/review-engine.js +48 -0
  53. package/server/dist/features/learning/engines/review-engine.test.js +59 -0
  54. package/server/dist/features/learning/engines/scheduler.js +60 -0
  55. package/server/dist/features/learning/engines/scheduler.test.js +61 -0
  56. package/server/dist/features/learning/learning.config.js +53 -0
  57. package/server/dist/features/learning/learning.config.test.js +34 -0
  58. package/server/dist/features/learning/learning.controller.js +145 -0
  59. package/server/dist/features/learning/learning.repository.js +334 -0
  60. package/server/dist/features/learning/learning.service.js +496 -0
  61. package/server/dist/features/learning/learning.types.js +1 -0
  62. package/server/dist/features/lessons/lessons.controller.js +126 -0
  63. package/server/dist/features/lessons/lessons.repository.js +56 -0
  64. package/server/dist/features/lessons/lessons.service.js +155 -0
  65. package/server/dist/features/lessons/stream.service.js +94 -0
  66. package/server/dist/features/lessons/text-content.js +294 -0
  67. package/server/dist/features/lessons/text-content.test.js +278 -0
  68. package/server/dist/features/notes/notes.controller.js +91 -0
  69. package/server/dist/features/notes/notes.repository.js +50 -0
  70. package/server/dist/features/notes/notes.service.js +78 -0
  71. package/server/dist/features/profile/profile.controller.js +81 -0
  72. package/server/dist/features/profile/profile.repository.js +41 -0
  73. package/server/dist/features/profile/profile.service.js +128 -0
  74. package/server/dist/features/progress/progress.controller.js +58 -0
  75. package/server/dist/features/progress/progress.repository.js +64 -0
  76. package/server/dist/features/progress/progress.service.js +39 -0
  77. package/server/dist/features/settings/settings.controller.js +54 -0
  78. package/server/dist/features/settings/settings.repository.js +33 -0
  79. package/server/dist/features/settings/settings.service.js +173 -0
  80. package/server/dist/features/settings/text-mode.js +21 -0
  81. package/server/dist/features/settings/text-mode.test.js +28 -0
  82. package/server/dist/features/stats/stats.controller.js +32 -0
  83. package/server/dist/features/stats/stats.repository.js +39 -0
  84. package/server/dist/features/stats/stats.service.js +114 -0
  85. package/server/dist/features/system/system.controller.js +86 -0
  86. package/server/dist/index.js +144 -0
  87. package/server/dist/shared/api-error.js +7 -0
  88. package/server/dist/shared/app-lifecycle.js +11 -0
  89. package/server/dist/shared/binary.js +90 -0
  90. package/server/dist/shared/dependencies.js +90 -0
  91. package/server/dist/shared/logging.js +295 -0
  92. package/server/dist/shared/natural-sort.js +11 -0
  93. package/server/dist/shared/server-info.js +70 -0
  94. package/server/dist/shared/slug.js +20 -0
  95. package/server/dist/shared/uuid.js +41 -0
  96. package/server/dist/shared/uuid.test.js +23 -0
  97. package/server/dist/types.js +1 -0
  98. package/server/migrations/0001_baseline.up.sql +82 -0
  99. package/server/migrations/0002_enrichment.down.sql +11 -0
  100. package/server/migrations/0002_enrichment.up.sql +143 -0
  101. package/server/migrations/0003_course_enrich_opt_in.down.sql +1 -0
  102. package/server/migrations/0003_course_enrich_opt_in.up.sql +1 -0
  103. package/server/migrations/0004_learning_engine.down.sql +7 -0
  104. package/server/migrations/0004_learning_engine.up.sql +101 -0
  105. package/server/migrations/0005_text_progress.down.sql +1 -0
  106. package/server/migrations/0005_text_progress.up.sql +2 -0
package/README.md CHANGED
@@ -1,3 +1,211 @@
1
- # Temporary Holding Version
1
+ # Coursy
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Local-first AI study companion for downloaded video and text courses. Point it at a folder of
4
+ course videos; it plays them like a curriculum, tracks progress, and builds an AI layer on top:
5
+ per-lesson summaries, scene navigation, practice questions, voice mock interviews, and a
6
+ personalized study plan.
7
+
8
+ ## Requirements
9
+
10
+ - Node.js **22.13+**
11
+ - `ffmpeg` + `ffprobe` on PATH — needed for AI enrichment only; playback works without them:
12
+ - macOS: `brew install ffmpeg`
13
+ - Windows: `winget install Gyan.FFmpeg` (or `choco install ffmpeg`)
14
+ - Linux: `sudo apt install ffmpeg` (Fedora: `sudo dnf install ffmpeg`, Arch: `sudo pacman -S ffmpeg`)
15
+ - Custom installs: `COURSY_FFMPEG_PATH` / `COURSY_FFPROBE_PATH` (file or directory)
16
+ - Optional: an OpenAI-compatible LLM key (DeepSeek, OpenCode Go, OpenAI, OpenRouter, Ollama, …)
17
+ - Optional transcription: subtitles (`.srt`/`.vtt`) next to videos, a Whisper-compatible API key, or
18
+ FluidAudio on macOS for fully local transcription
19
+
20
+ Missing dependencies never break playback: Coursy shows a warning with the exact fix in
21
+ `coursy doctor`, `coursy status`, the web UI, and disables enrichment actions with the
22
+ reason.
23
+
24
+ ## Data directory
25
+
26
+ Everything lives in one folder — `~/.coursy` on every OS (override with
27
+ `COURSY_DATA_DIR` or `--data-dir`):
28
+
29
+ | OS | Path |
30
+ |---|---|
31
+ | macOS | `/Users/<user>/.coursy` |
32
+ | Linux | `/home/<user>/.coursy` |
33
+ | Windows | `C:\Users\<user>\.coursy` (cmd/PowerShell: `%USERPROFILE%\.coursy`) |
34
+
35
+ It contains `coursy.db`, `media/`, `artifacts/`, `thumbs/`, `coursy.log` and
36
+ `server.json`. Course folders are never written to.
37
+
38
+ Upgrading from Opencourser: the first run after the rename copies `~/.opencourser` into
39
+ `~/.coursy` automatically (database, media, artifacts, thumbnails). Legacy `OPENCOURSER_*`
40
+ environment variables are still honored, and the `opencourser` command keeps working as an alias
41
+ for `coursy`.
42
+
43
+ ## Quick start
44
+
45
+ ```bash
46
+ npx @priyadarship4/coursy # start the server and open the UI (foreground)
47
+ npx @priyadarship4/coursy start --d # start in the background (daemon)
48
+ npx @priyadarship4/coursy play ~/courses # add/scan a course folder and open it
49
+ npx @priyadarship4/coursy status # server, queue, storage and setup status
50
+ npx @priyadarship4/coursy stats # learning, ai and server stats
51
+ npx @priyadarship4/coursy logs -f # tail the log (JSON lines on disk)
52
+ npx @priyadarship4/coursy doctor # check ffmpeg, transcription and LLM setup
53
+ ```
54
+
55
+ Keep a course folder anywhere on disk — Coursy never writes to it. All state lives in
56
+ `~/.coursy` (override with `COURSY_DATA_DIR` or `--data-dir`).
57
+
58
+ The server runs on **`:4257`** by default (`http://127.0.0.1:4257`). If that port is taken by
59
+ another app, the CLI picks the next free one and tells you (`port 4257 is in use — using 4258`);
60
+ passing `--port` explicitly is strict and fails instead of shifting. The Vite dev client proxies
61
+ to `COURSY_PORT` (default `4257`).
62
+
63
+ ## CLI reference
64
+
65
+ | Command | What it does |
66
+ |---|---|
67
+ | `start` | Foreground server; `--detach` / `-d` / `--d` runs it in the background |
68
+ | `stop` / `restart` | Manage the background server (pid file: `~/.coursy/server.json`) |
69
+ | `status` | Version, uptime, memory, storage, queue, readiness, recent failures |
70
+ | `stats [learning\|ai\|server]` | Sections: watch time/streaks/practice, LLM + transcription usage, disk/queue health |
71
+ | `logs` | Tail logs; `-f` follow, `-n` lines, `--date`, `--level`, `--grep`, `--path`, `--prune`, `--json` |
72
+ | `config list\|get\|set\|unset` | Read/write settings (secrets masked); same whitelist as the Settings UI |
73
+ | `courses` | Course list with progress, enrichment and practice counts |
74
+ | `revisions [days]` | Due and upcoming spaced-repetition reviews (default 7 days) |
75
+ | `play <path>` | Scan a folder and open the course |
76
+ | `enrich <path\|id>` | Run enrichment for a whole course (`-f` to watch progress) |
77
+ | `remove <id\|slug>` | Delete a course with its AI artifacts, media cache and thumbnails |
78
+ | `export <id\|slug>` | Write summaries, rollups, master notes and the plan as markdown (`--out <dir>`) |
79
+ | `open` / `doctor` / `version` / `help` | Open the UI, environment checks, help |
80
+
81
+ Global flags: `--data-dir`, `--port`, `--host`, `--json`, `--quiet`, `--no-color`.
82
+ Long options accept unambiguous prefixes (`--det` → `--detach`); command-specific flags win
83
+ (`coursy start --d` → detach, `coursy logs --d` → date, `coursy stats --d` → days).
84
+
85
+ ## Logging
86
+
87
+ Server logs are JSON lines in `~/.coursy/coursy.log` (requests, enrichment pipeline,
88
+ LLM retries, slow SQLite queries, errors). Daily archives roll to `coursy-YYYY-MM-DD.log`;
89
+ files older than 3 days are gzipped and archives older than 30 days are deleted
90
+ (`COURSY_LOG_RETENTION_DAYS`, `COURSY_LOG_KEEP_DAYS`). Detached servers also pipe
91
+ stdout to `~/.coursy/coursy.out.log`.
92
+
93
+ ## AI setup
94
+
95
+ Open **Settings → AI enrichment**:
96
+
97
+ - **LLM**: base URL + model + API key (stored locally in SQLite, never sent anywhere except the
98
+ provider you configure). Use *Test* to verify. OpenCode Go works out of the box: base URL
99
+ `https://opencode.ai/zen/go/v1`, model `deepseek-v4.1-flash`; Coursy adds the required
100
+ `x-opencode-session` header automatically ([design](docs/OPENCODE_GO_LLD.md)).
101
+ - **Transcription** order in `auto` mode: existing subtitles → local FluidAudio (macOS) → Whisper API.
102
+ - **Interview**: prep timer, max answer length, strictness.
103
+
104
+ Enrichment is opt-in per course: check **Enrich this course** in the study setup (or start it from
105
+ the Enrichment tab). Once a course is opted in, opening a lesson enqueues it and prefetches the next
106
+ two, with an optional **Enrich course** batch run. Pause/resume/cancel and retry are always available;
107
+ the home page shows a live queue for every active course.
108
+
109
+ ## What it generates
110
+
111
+ | Artifact | Where |
112
+ |---|---|
113
+ | Lesson summary + key points | Enrichment tab |
114
+ | Scene thumbnails (click to seek) | Enrichment tab |
115
+ | Practice: MCQs (instant feedback) | Enrichment tab |
116
+ | Voice/typed mock interview with follow-ups and grading | Enrichment tab |
117
+ | Study plan from your goals and time budget | Plan drawer |
118
+ | Section rollups + master notes | Plan drawer → Notes |
119
+ | Markdown export bundle | Plan drawer → Export |
120
+
121
+ ## Spaced repetition
122
+
123
+ Practice generation also extracts 3–8 **concepts** per lesson and tags every question with
124
+ one. Finishing a quick check records per-concept evidence; concepts then resurface on a
125
+ `1/3/7/14/30/60`-day schedule (adaptive by default, `fail → tomorrow`, `hard → ×0.6`,
126
+ `good → next`, `easy → skip one`). Practice sessions never move the schedule — only
127
+ scheduled/manual reviews do.
128
+
129
+ | Surface | Where |
130
+ |---|---|
131
+ | Revision schedule rail (due now + 14-day agenda) | Home → right rail |
132
+ | Review dialog (MCQ + confidence → mastery/next due) | Home → Revision schedule · `coursy revisions` in the terminal |
133
+ | Concept mastery, performance curve, improvement insights | Stats |
134
+
135
+ Settings (`/api/settings`, `settings` table): `learning_preset`
136
+ (`relaxed|standard|intensive|custom`), `learning_steps`, `learning_adaptive`,
137
+ `learning_daily_target_min`, `learning_preferred_time` — global with per-course overrides.
138
+ Full design: [`docs/LEARNING_ENGINE_LLD.md`](docs/LEARNING_ENGINE_LLD.md).
139
+
140
+ ## Development
141
+
142
+ ```bash
143
+ npm install
144
+ npm run dev # server on :4257 + Vite dev client
145
+ npm run build # production build (client + server)
146
+ npm run doctor
147
+ ```
148
+
149
+ Data model and architecture: [`docs/ENRICHMENT_MERGE_LLD.md`](docs/ENRICHMENT_MERGE_LLD.md).
150
+
151
+ ## Testing
152
+
153
+ **Unit (no API keys needed).** Scheduler, mastery EMA, review engine, concept
154
+ normalization and UUIDv7:
155
+
156
+ ```bash
157
+ npm run test:unit
158
+ ```
159
+
160
+ **Automated (no API keys needed).** Builds both workspaces, generates a synthetic course with
161
+ ffmpeg (2 scene cuts, an `.srt` sidecar, a text lesson), runs a local mock OpenAI-compatible
162
+ server, and exercises the full pipeline through the real HTTP API:
163
+
164
+ ```bash
165
+ npm run test:e2e
166
+ ```
167
+
168
+ 90+ checks cover: scan → queue → extract → subtitle/Whisper transcription → align → summarize →
169
+ practice; persona/goal prompt injection; study plan; typed and voice interview turns with
170
+ follow-ups; pause/resume; dry-run without a key; section rollups; master notes; export; plus
171
+ enrichment consent gating (prefetch skipped until opt-in), the live queue payload, and course
172
+ deletion (DB cascade + on-disk cleanup).
173
+ Fixtures and the test database are kept under `$TMPDIR/coursy-e2e` for inspection.
174
+
175
+ CLI lifecycle, logging, rotation and config round-trips are covered by:
176
+
177
+ ```bash
178
+ npm run test:cli
179
+ ```
180
+
181
+ **Manual (real browser).**
182
+
183
+ ```bash
184
+ npm run dev
185
+ # open http://localhost:5173
186
+ ```
187
+
188
+ 1. `Settings → AI enrichment`: add your LLM key and press *Test*. Optionally set the FluidAudio
189
+ binary path for local macOS transcription.
190
+ 2. Drop a course folder path on the home page (or run `node bin/coursy.mjs play <path>`).
191
+ 3. The full-screen **study setup** opens: persona (level, weak areas), course goal (struggles,
192
+ deadline), then the enrichment opt-in with a first-lesson or whole-course scope, and finally the
193
+ study plan. Nothing is enriched until you check the opt-in.
194
+ 4. Open the first lesson — enrichment follows your opt-in. Watch `Enrichment` for the summary, scene
195
+ thumbnails (click one to seek the video), MCQs and the mock interview (allow microphone access
196
+ to answer out loud). Use `Plan` for rollups, master notes and the markdown export, and `Setup` to
197
+ change your profile, goal or consent later.
198
+ 5. Check `node bin/coursy.mjs doctor` for ffmpeg/FluidAudio/LLM readiness, and
199
+ `node bin/coursy.mjs enrich <path>` for a headless full-course run. Remove courses from the
200
+ card `⋯ → Remove course` menu or with `coursy remove <id|slug>`.
201
+
202
+ To test the real FluidAudio path, set the binary once:
203
+
204
+ ```bash
205
+ export FLUIDAUDIO_BIN="/path/to/course-extractor/vendor/FluidAudio/.build/release/fluidaudiocli"
206
+ ```
207
+
208
+
209
+ ## License
210
+
211
+ MIT