coursecode 0.1.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 (362) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +322 -0
  3. package/THIRD_PARTY_NOTICES.md +22 -0
  4. package/bin/cli.js +331 -0
  5. package/framework/assets/logo-coursecode-black.svg +14 -0
  6. package/framework/assets/logo-coursecode-white.svg +14 -0
  7. package/framework/assets/logo-coursecode.svg +14 -0
  8. package/framework/css/01-base.css +160 -0
  9. package/framework/css/02-layout.css +499 -0
  10. package/framework/css/accessibility.css +834 -0
  11. package/framework/css/components/accordions.css +710 -0
  12. package/framework/css/components/assessments.css +520 -0
  13. package/framework/css/components/audio-player.css +570 -0
  14. package/framework/css/components/badges.css +80 -0
  15. package/framework/css/components/breadcrumbs.css +87 -0
  16. package/framework/css/components/buttons.css +707 -0
  17. package/framework/css/components/callouts.css +1280 -0
  18. package/framework/css/components/cards.css +475 -0
  19. package/framework/css/components/carousel.css +193 -0
  20. package/framework/css/components/checkbox-group.css +123 -0
  21. package/framework/css/components/checklist.css +203 -0
  22. package/framework/css/components/collapse.css +96 -0
  23. package/framework/css/components/comparison.css +33 -0
  24. package/framework/css/components/content-image.css +36 -0
  25. package/framework/css/components/document-gallery.css +425 -0
  26. package/framework/css/components/dropdown.css +115 -0
  27. package/framework/css/components/embed-frame.css +142 -0
  28. package/framework/css/components/engagement.css +412 -0
  29. package/framework/css/components/features.css +35 -0
  30. package/framework/css/components/flip-cards.css +253 -0
  31. package/framework/css/components/footer.css +353 -0
  32. package/framework/css/components/forms.css +294 -0
  33. package/framework/css/components/hero.css +216 -0
  34. package/framework/css/components/images.css +528 -0
  35. package/framework/css/components/interactive-timeline.css +274 -0
  36. package/framework/css/components/intro-cards.css +30 -0
  37. package/framework/css/components/lightbox.css +666 -0
  38. package/framework/css/components/loading.css +65 -0
  39. package/framework/css/components/modals.css +235 -0
  40. package/framework/css/components/notifications.css +107 -0
  41. package/framework/css/components/quote.css +150 -0
  42. package/framework/css/components/sidebar.css +684 -0
  43. package/framework/css/components/slide-header.css +52 -0
  44. package/framework/css/components/spinner.css +62 -0
  45. package/framework/css/components/stats.css +44 -0
  46. package/framework/css/components/steps.css +232 -0
  47. package/framework/css/components/tables.css +90 -0
  48. package/framework/css/components/tabs.css +347 -0
  49. package/framework/css/components/timeline.css +154 -0
  50. package/framework/css/components/toggle.css +95 -0
  51. package/framework/css/components/tooltip.css +226 -0
  52. package/framework/css/components/video-player.css +438 -0
  53. package/framework/css/design-tokens.css +707 -0
  54. package/framework/css/framework.css +86 -0
  55. package/framework/css/interactions/accessibility.css +75 -0
  56. package/framework/css/interactions/base.css +92 -0
  57. package/framework/css/interactions/drag-drop.css +295 -0
  58. package/framework/css/interactions/fill-in-the-blank.css +236 -0
  59. package/framework/css/interactions/hotspots.css +69 -0
  60. package/framework/css/interactions/index.css +45 -0
  61. package/framework/css/interactions/interactive-image.css +359 -0
  62. package/framework/css/interactions/likert.css +126 -0
  63. package/framework/css/interactions/matching.css +354 -0
  64. package/framework/css/interactions/numeric-input.css +78 -0
  65. package/framework/css/interactions/sequencing.css +378 -0
  66. package/framework/css/interactions/true-false.css +177 -0
  67. package/framework/css/layouts/article.css +258 -0
  68. package/framework/css/layouts/base.css +30 -0
  69. package/framework/css/layouts/canvas.css +38 -0
  70. package/framework/css/layouts/focused.css +236 -0
  71. package/framework/css/layouts/index.css +29 -0
  72. package/framework/css/layouts/presentation.css +191 -0
  73. package/framework/css/layouts/traditional.css +52 -0
  74. package/framework/css/responsive.css +439 -0
  75. package/framework/css/utilities/accessibility-utils.css +59 -0
  76. package/framework/css/utilities/animations.css +419 -0
  77. package/framework/css/utilities/borders.css +72 -0
  78. package/framework/css/utilities/colors.css +76 -0
  79. package/framework/css/utilities/container.css +46 -0
  80. package/framework/css/utilities/decorative.css +442 -0
  81. package/framework/css/utilities/display.css +257 -0
  82. package/framework/css/utilities/flexbox.css +80 -0
  83. package/framework/css/utilities/grid.css +69 -0
  84. package/framework/css/utilities/icons.css +534 -0
  85. package/framework/css/utilities/lists.css +190 -0
  86. package/framework/css/utilities/spacing.css +167 -0
  87. package/framework/css/utilities/tables.css +81 -0
  88. package/framework/css/utilities/typography.css +159 -0
  89. package/framework/css/utilities/visibility.css +117 -0
  90. package/framework/docs/COURSE_AUTHORING_GUIDE.md +1773 -0
  91. package/framework/docs/COURSE_OUTLINE_GUIDE.md +725 -0
  92. package/framework/docs/COURSE_OUTLINE_TEMPLATE.md +161 -0
  93. package/framework/docs/DATA_MODEL.md +409 -0
  94. package/framework/docs/FRAMEWORK_GUIDE.md +1088 -0
  95. package/framework/docs/USER_GUIDE.md +583 -0
  96. package/framework/docs/examples/cloudflare-channel-relay.js +169 -0
  97. package/framework/docs/examples/cloudflare-data-worker.js +102 -0
  98. package/framework/docs/examples/cloudflare-error-worker.js +228 -0
  99. package/framework/index.html +175 -0
  100. package/framework/js/app/AppActions.js +410 -0
  101. package/framework/js/app/AppState.js +225 -0
  102. package/framework/js/app/AppUI.js +616 -0
  103. package/framework/js/assessment/AssessmentActions.js +615 -0
  104. package/framework/js/assessment/AssessmentFactory.js +471 -0
  105. package/framework/js/assessment/AssessmentState.js +322 -0
  106. package/framework/js/assessment/AssessmentUI.js +451 -0
  107. package/framework/js/automation/api-engagement.js +196 -0
  108. package/framework/js/automation/api-interactions.js +167 -0
  109. package/framework/js/automation/api.js +242 -0
  110. package/framework/js/automation/index.js +41 -0
  111. package/framework/js/components/interactions/drag-drop.js +884 -0
  112. package/framework/js/components/interactions/fill-in.js +535 -0
  113. package/framework/js/components/interactions/hotspot.js +702 -0
  114. package/framework/js/components/interactions/interaction-base.js +511 -0
  115. package/framework/js/components/interactions/likert.js +301 -0
  116. package/framework/js/components/interactions/matching.js +699 -0
  117. package/framework/js/components/interactions/multiple-choice.js +377 -0
  118. package/framework/js/components/interactions/numeric.js +271 -0
  119. package/framework/js/components/interactions/sequencing.js +423 -0
  120. package/framework/js/components/interactions/true-false.js +241 -0
  121. package/framework/js/components/ui-components/accordion.js +442 -0
  122. package/framework/js/components/ui-components/alert.js +88 -0
  123. package/framework/js/components/ui-components/audio-player.js +1193 -0
  124. package/framework/js/components/ui-components/callout.js +121 -0
  125. package/framework/js/components/ui-components/carousel.js +145 -0
  126. package/framework/js/components/ui-components/checkbox-group.js +87 -0
  127. package/framework/js/components/ui-components/checklist.js +40 -0
  128. package/framework/js/components/ui-components/collapse.js +114 -0
  129. package/framework/js/components/ui-components/comparison.js +30 -0
  130. package/framework/js/components/ui-components/conditional-display.js +150 -0
  131. package/framework/js/components/ui-components/content-image.js +41 -0
  132. package/framework/js/components/ui-components/dropdown.js +262 -0
  133. package/framework/js/components/ui-components/embed-frame.js +274 -0
  134. package/framework/js/components/ui-components/features.js +33 -0
  135. package/framework/js/components/ui-components/flip-card.js +230 -0
  136. package/framework/js/components/ui-components/form-validator.js +76 -0
  137. package/framework/js/components/ui-components/hero.js +49 -0
  138. package/framework/js/components/ui-components/index.js +12 -0
  139. package/framework/js/components/ui-components/interactive-image.js +235 -0
  140. package/framework/js/components/ui-components/interactive-timeline.js +285 -0
  141. package/framework/js/components/ui-components/intro-cards.js +35 -0
  142. package/framework/js/components/ui-components/lightbox.js +652 -0
  143. package/framework/js/components/ui-components/modal.js +386 -0
  144. package/framework/js/components/ui-components/notifications.js +145 -0
  145. package/framework/js/components/ui-components/progress.js +88 -0
  146. package/framework/js/components/ui-components/quote.js +41 -0
  147. package/framework/js/components/ui-components/stats.js +33 -0
  148. package/framework/js/components/ui-components/steps.js +41 -0
  149. package/framework/js/components/ui-components/tabs.js +255 -0
  150. package/framework/js/components/ui-components/timeline.js +42 -0
  151. package/framework/js/components/ui-components/toggle-group.js +73 -0
  152. package/framework/js/components/ui-components/tooltip.js +458 -0
  153. package/framework/js/components/ui-components/value-display.js +133 -0
  154. package/framework/js/components/ui-components/video-player.js +686 -0
  155. package/framework/js/core/component-catalog.js +121 -0
  156. package/framework/js/core/event-bus.js +178 -0
  157. package/framework/js/core/interaction-catalog.js +149 -0
  158. package/framework/js/dev/runtime-linter.js +1725 -0
  159. package/framework/js/drivers/cmi5-driver.js +768 -0
  160. package/framework/js/drivers/driver-factory.js +77 -0
  161. package/framework/js/drivers/driver-interface.js +110 -0
  162. package/framework/js/drivers/http-driver-base.js +241 -0
  163. package/framework/js/drivers/lti-driver.js +508 -0
  164. package/framework/js/drivers/proxy-driver.js +444 -0
  165. package/framework/js/drivers/scorm-12-driver.js +560 -0
  166. package/framework/js/drivers/scorm-2004-driver.js +775 -0
  167. package/framework/js/drivers/scorm-driver-base.js +112 -0
  168. package/framework/js/engagement/engagement-manager.js +404 -0
  169. package/framework/js/engagement/engagement-progress.js +191 -0
  170. package/framework/js/engagement/engagement-trackers.js +215 -0
  171. package/framework/js/engagement/requirement-strategies.js +268 -0
  172. package/framework/js/main.js +727 -0
  173. package/framework/js/managers/accessibility-manager.js +499 -0
  174. package/framework/js/managers/assessment-manager.js +230 -0
  175. package/framework/js/managers/audio-manager.js +944 -0
  176. package/framework/js/managers/comment-manager.js +88 -0
  177. package/framework/js/managers/flag-manager.js +86 -0
  178. package/framework/js/managers/interaction-manager.js +254 -0
  179. package/framework/js/managers/interaction-registry.js +96 -0
  180. package/framework/js/managers/objective-manager.js +423 -0
  181. package/framework/js/managers/score-manager.js +441 -0
  182. package/framework/js/managers/video-manager.js +536 -0
  183. package/framework/js/navigation/Breadcrumbs.js +234 -0
  184. package/framework/js/navigation/NavigationActions.js +1132 -0
  185. package/framework/js/navigation/NavigationState.js +276 -0
  186. package/framework/js/navigation/NavigationUI.js +574 -0
  187. package/framework/js/navigation/document-gallery.js +357 -0
  188. package/framework/js/navigation/navigation-helpers.js +175 -0
  189. package/framework/js/navigation/navigation-validators.js +174 -0
  190. package/framework/js/state/index.js +8 -0
  191. package/framework/js/state/lms-connection.js +482 -0
  192. package/framework/js/state/lms-error-utils.js +58 -0
  193. package/framework/js/state/state-commits.js +200 -0
  194. package/framework/js/state/state-domains.js +86 -0
  195. package/framework/js/state/state-manager.js +502 -0
  196. package/framework/js/state/state-validation.js +311 -0
  197. package/framework/js/state/transaction-log.js +41 -0
  198. package/framework/js/state/xapi-statement-service.js +325 -0
  199. package/framework/js/utilities/access-control.js +99 -0
  200. package/framework/js/utilities/breakpoint-manager.js +315 -0
  201. package/framework/js/utilities/canvas-slide.js +35 -0
  202. package/framework/js/utilities/conditional-display.js +388 -0
  203. package/framework/js/utilities/course-channel.js +214 -0
  204. package/framework/js/utilities/course-helpers.js +420 -0
  205. package/framework/js/utilities/data-reporter.js +273 -0
  206. package/framework/js/utilities/error-reporter.js +313 -0
  207. package/framework/js/utilities/hotspot-helper.js +341 -0
  208. package/framework/js/utilities/icons.js +348 -0
  209. package/framework/js/utilities/logger.js +92 -0
  210. package/framework/js/utilities/markdown-renderer.js +45 -0
  211. package/framework/js/utilities/scroll-tracker.js +68 -0
  212. package/framework/js/utilities/ui-initializer.js +146 -0
  213. package/framework/js/utilities/utilities.js +293 -0
  214. package/framework/js/utilities/view-manager.js +227 -0
  215. package/framework/js/validation/html-validators.js +422 -0
  216. package/framework/js/validation/scorm-validators.js +438 -0
  217. package/framework/js/vendor/pipwerks.js +931 -0
  218. package/framework/scripts/generate-narration.js +629 -0
  219. package/framework/scripts/tts-providers/azure-provider.js +178 -0
  220. package/framework/scripts/tts-providers/base-provider.js +81 -0
  221. package/framework/scripts/tts-providers/deepgram-provider.js +135 -0
  222. package/framework/scripts/tts-providers/elevenlabs-provider.js +148 -0
  223. package/framework/scripts/tts-providers/google-provider.js +272 -0
  224. package/framework/scripts/tts-providers/index.js +158 -0
  225. package/framework/scripts/tts-providers/openai-provider.js +143 -0
  226. package/framework/version.json +63 -0
  227. package/lib/authoring-api.js +919 -0
  228. package/lib/build-linter.js +450 -0
  229. package/lib/build-packaging.js +186 -0
  230. package/lib/build.js +88 -0
  231. package/lib/cloud.js +691 -0
  232. package/lib/convert.js +341 -0
  233. package/lib/course-parser.js +936 -0
  234. package/lib/course-writer.js +258 -0
  235. package/lib/create.js +248 -0
  236. package/lib/css-index.js +237 -0
  237. package/lib/dev.js +51 -0
  238. package/lib/export-content.js +1246 -0
  239. package/lib/headless-browser.js +413 -0
  240. package/lib/import.js +377 -0
  241. package/lib/index.js +80 -0
  242. package/lib/info.js +79 -0
  243. package/lib/interaction-formatters.js +568 -0
  244. package/lib/manifest/cmi5-manifest.js +63 -0
  245. package/lib/manifest/lti-tool-config.js +53 -0
  246. package/lib/manifest/manifest-factory.js +99 -0
  247. package/lib/manifest/scorm-12-manifest.js +61 -0
  248. package/lib/manifest/scorm-2004-manifest.js +94 -0
  249. package/lib/manifest/scorm-proxy-manifest.js +104 -0
  250. package/lib/manifest-parser.js +96 -0
  251. package/lib/mcp-prompts.js +753 -0
  252. package/lib/mcp-server.js +316 -0
  253. package/lib/narration.js +53 -0
  254. package/lib/pdf-structure.js +142 -0
  255. package/lib/preview-export.js +231 -0
  256. package/lib/preview-routes-api.js +662 -0
  257. package/lib/preview-routes-editing.js +159 -0
  258. package/lib/preview-routes-lms.js +230 -0
  259. package/lib/preview-server.js +564 -0
  260. package/lib/project-utils.js +269 -0
  261. package/lib/proxy-templates/proxy.html +68 -0
  262. package/lib/proxy-templates/scorm-bridge.js +112 -0
  263. package/lib/scaffold.js +193 -0
  264. package/lib/schema-extractor.js +361 -0
  265. package/lib/slide-source-editor.js +586 -0
  266. package/lib/stub-player/app-viewer.js +195 -0
  267. package/lib/stub-player/app.js +370 -0
  268. package/lib/stub-player/catalog-panel.js +312 -0
  269. package/lib/stub-player/config-panel.js +1303 -0
  270. package/lib/stub-player/content-generator.js +586 -0
  271. package/lib/stub-player/content-viewer.js +173 -0
  272. package/lib/stub-player/debug-panel.js +420 -0
  273. package/lib/stub-player/edit-mode.js +922 -0
  274. package/lib/stub-player/edit-utils.js +400 -0
  275. package/lib/stub-player/header-bar.js +354 -0
  276. package/lib/stub-player/interaction-editor.js +210 -0
  277. package/lib/stub-player/interactions-panel.js +565 -0
  278. package/lib/stub-player/lms-api.js +1094 -0
  279. package/lib/stub-player/login-screen.js +74 -0
  280. package/lib/stub-player/outline-mode.js +689 -0
  281. package/lib/stub-player/styles/_assessments-panel.css +245 -0
  282. package/lib/stub-player/styles/_base.css +89 -0
  283. package/lib/stub-player/styles/_catalog-icons.css +96 -0
  284. package/lib/stub-player/styles/_catalog-panel.css +291 -0
  285. package/lib/stub-player/styles/_config-panel.css +636 -0
  286. package/lib/stub-player/styles/_content-viewer.css +834 -0
  287. package/lib/stub-player/styles/_debug-panel.css +576 -0
  288. package/lib/stub-player/styles/_edit-mode.css +128 -0
  289. package/lib/stub-player/styles/_header-bar.css +343 -0
  290. package/lib/stub-player/styles/_interaction-editor.css +140 -0
  291. package/lib/stub-player/styles/_interactions-panel.css +1038 -0
  292. package/lib/stub-player/styles/_login-screen.css +102 -0
  293. package/lib/stub-player/styles/_outline-mode.css +752 -0
  294. package/lib/stub-player/styles.css +15 -0
  295. package/lib/stub-player.js +160 -0
  296. package/lib/test-data-reporting.js +176 -0
  297. package/lib/test-error-reporting.js +146 -0
  298. package/lib/token.js +86 -0
  299. package/lib/upgrade.js +257 -0
  300. package/lib/validation-rules.js +517 -0
  301. package/lib/vite-plugin-content-discovery.js +296 -0
  302. package/package.json +108 -0
  303. package/schemas/XMLSchema.dtd +402 -0
  304. package/schemas/adlcp_v1p3.xsd +111 -0
  305. package/schemas/adlnav_v1p3.xsd +61 -0
  306. package/schemas/adlseq_v1p3.xsd +93 -0
  307. package/schemas/common/anyElement.xsd +27 -0
  308. package/schemas/common/dataTypes.xsd +138 -0
  309. package/schemas/common/elementNames.xsd +767 -0
  310. package/schemas/common/elementTypes.xsd +786 -0
  311. package/schemas/common/rootElement.xsd +31 -0
  312. package/schemas/common/vocabTypes.xsd +345 -0
  313. package/schemas/common/vocabValues.xsd +257 -0
  314. package/schemas/datatypes.dtd +203 -0
  315. package/schemas/ims_xml.xsd +35 -0
  316. package/schemas/imscp_v1p1.xsd +368 -0
  317. package/schemas/imsss_v1p0.xsd +67 -0
  318. package/schemas/imsss_v1p0auxresource.xsd +19 -0
  319. package/schemas/imsss_v1p0control.xsd +20 -0
  320. package/schemas/imsss_v1p0delivery.xsd +17 -0
  321. package/schemas/imsss_v1p0limit.xsd +47 -0
  322. package/schemas/imsss_v1p0objective.xsd +67 -0
  323. package/schemas/imsss_v1p0random.xsd +16 -0
  324. package/schemas/imsss_v1p0rollup.xsd +46 -0
  325. package/schemas/imsss_v1p0seqrule.xsd +108 -0
  326. package/schemas/imsss_v1p0util.xsd +94 -0
  327. package/schemas/license.txt +17 -0
  328. package/schemas/lom.xsd +102 -0
  329. package/schemas/lomCustom.xsd +62 -0
  330. package/schemas/lomLoose.xsd +62 -0
  331. package/schemas/lomStrict.xsd +62 -0
  332. package/schemas/xml.xsd +81 -0
  333. package/template/.env.example +92 -0
  334. package/template/course/assets/audio/example-intro.mp3 +0 -0
  335. package/template/course/assets/audio/example-ui-demo--compact-player.mp3 +0 -0
  336. package/template/course/assets/audio/example-ui-demo--demo-modal.mp3 +0 -0
  337. package/template/course/assets/audio/example-ui-demo--full-player.mp3 +0 -0
  338. package/template/course/assets/docs/example_md_1.md +39 -0
  339. package/template/course/assets/docs/example_md_2.md +41 -0
  340. package/template/course/assets/docs/example_pdf_1_thumbnail.png +0 -0
  341. package/template/course/assets/docs/example_pdf_2.pdf +0 -0
  342. package/template/course/assets/images/course-architecture.svg +36 -0
  343. package/template/course/assets/images/logo.svg +14 -0
  344. package/template/course/assets/widgets/counter-demo.html +190 -0
  345. package/template/course/assets/widgets/gravity-painter.html +384 -0
  346. package/template/course/course-config.js +539 -0
  347. package/template/course/icons.js +19 -0
  348. package/template/course/interactions/PLUGIN_GUIDE.md +97 -0
  349. package/template/course/slides/example-course-structure.js +138 -0
  350. package/template/course/slides/example-final-exam.js +144 -0
  351. package/template/course/slides/example-finishing.js +127 -0
  352. package/template/course/slides/example-interactions-showcase.js +615 -0
  353. package/template/course/slides/example-preview-tour.js +129 -0
  354. package/template/course/slides/example-remedial.js +143 -0
  355. package/template/course/slides/example-summary.js +103 -0
  356. package/template/course/slides/example-ui-showcase.js +1805 -0
  357. package/template/course/slides/example-welcome.js +123 -0
  358. package/template/course/slides/example-workflow.js +140 -0
  359. package/template/course/theme.css +165 -0
  360. package/template/eslint.config.js +47 -0
  361. package/template/package.json +28 -0
  362. package/template/vite.config.js +339 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Seth Vincent
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,322 @@
1
+ # CourseCode
2
+
3
+ **A modern framework for building interactive e-learning courses with AI-assisted authoring.**
4
+
5
+ Drop in your existing PDFs, Word docs, or PowerPoints — AI converts them into complete, interactive courses. No vendor lock-in, no subscriptions. Your content, your code, deployed to any LMS.
6
+
7
+ ## Features
8
+
9
+ - 🔌 **MCP integration**: AI connects directly to your course — previews, screenshots, linting, and testing without manual file sharing
10
+ - 🎓 **Full LMS integration**: SCORM 1.2, SCORM 2004, cmi5, and LTI with complete tracking records
11
+ - 🤖 **AI-ready authoring**: Structured guides and MCP tools for AI-assisted course development
12
+ - 🧩 **Rich UI components**: Images, video, accordions, tabs, and custom sandboxed HTML/JS embeds
13
+ - 🎯 **Rich interactions**: Multiple choice, drag-drop, fill-in-the-blank, matching, sequencing, and more
14
+ - ♿ **Fully accessible**: WCAG 2.1 AA compliant with dark mode, high contrast, and reduced motion
15
+ - 🔊 **TTS audio narration**: Built-in player with AI text-to-speech generation (ElevenLabs, Deepgram, Google, BYO API Key)
16
+ - 📊 **Smart tracking**: Engagement requirements, learning objectives, and progress persistence
17
+ - 🎨 **Themeable design**: CSS custom properties for easy brand customization
18
+ - 🔗 **Custom endpoints**: Optional webhooks for error reporting and learning record storage
19
+ - 📥 **Drop-in content conversion**: Feed existing PDFs, Word docs, or PowerPoint files to AI and get a complete, interactive course
20
+ - 🖥️ **Live preview**: Visual editing, status dashboard, config panels, catalog browser, and full LMS simulation with debug tools
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ ### Required
27
+
28
+ Install [Node.js](https://nodejs.org/) (v18 or later), then run:
29
+
30
+ ```bash
31
+ npm install -g coursecode
32
+ ```
33
+
34
+ ### Recommended
35
+
36
+ - A code or text editor — [VS Code](https://code.visualstudio.com/), [Cursor](https://cursor.com/), or similar
37
+ - An AI coding assistant with MCP support — [Claude Code](https://claude.ai/code), [Cursor](https://cursor.com/), [Windsurf](https://codeium.com/windsurf), etc.
38
+ - [GitHub Desktop](https://desktop.github.com/) for version control
39
+
40
+ ---
41
+
42
+ ## Quick Start
43
+
44
+ ```bash
45
+
46
+ # Create a new course project
47
+ coursecode create my-course
48
+ cd my-course
49
+
50
+ # Start the preview server
51
+ coursecode preview
52
+ ```
53
+
54
+ Open `http://localhost:4173` to view and edit your course.
55
+
56
+ The example course included with every new project is a complete guide to using CourseCode.
57
+
58
+ 📖 **New to CourseCode?** Read the [User Guide](framework/docs/USER_GUIDE.md) for step-by-step instructions.
59
+
60
+ ---
61
+
62
+ ## MCP Integration
63
+
64
+ CourseCode includes a built-in [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server. When your AI tool supports MCP, it connects directly to your course project — no manual file sharing needed.
65
+
66
+ ```bash
67
+ coursecode mcp
68
+ ```
69
+
70
+ With MCP, your AI can:
71
+ - **Preview and screenshot** slides to verify layout and design
72
+ - **Lint its own code** and catch errors automatically
73
+ - **Navigate and test** interactions directly
74
+ - **Browse the component catalog** to discover available UI elements
75
+ - **Read course state** including engagement, scoring, and LMS data
76
+
77
+ See the [User Guide](framework/docs/USER_GUIDE.md#mcp-model-context-protocol) for setup instructions.
78
+
79
+ ---
80
+
81
+ ## The Course Directory
82
+
83
+ All your course content lives in the `course/` folder:
84
+
85
+ ```
86
+ my-course/
87
+ ├── course/ # ← Your content goes here
88
+ │ ├── course-config.js # Course structure, format, objectives, settings
89
+ │ ├── slides/ # Slide content files
90
+ │ │ ├── intro.js
91
+ │ │ ├── content-01.js
92
+ │ │ └── assessment.js
93
+ │ ├── assets/ # Images, audio, video
94
+ │ │ ├── images/
95
+ │ │ └── audio/
96
+ │ ├── theme.css # Brand customization
97
+
98
+ ├── framework/ # Framework code (don't edit)
99
+ │ └── docs/ # Guides and templates
100
+ ```
101
+
102
+ ### Your Course
103
+
104
+ | Location | What's There |
105
+ |----------|--------------|
106
+ | `course/course-config.js` | Course settings — structure, objectives, navigation rules |
107
+ | `course/slides/` | Your slide content (one file per slide) |
108
+ | `course/theme.css` | Brand colors and typography |
109
+ | `course/assets/` | Images, audio, and video files |
110
+
111
+ ### Key Documentation
112
+
113
+ All guides are in `framework/docs/`:
114
+
115
+ | Document | Audience | Purpose |
116
+ |----------|----------|---------|
117
+ | `README.md` | Humans | Project overview and getting started |
118
+ | `USER_GUIDE.md` | Humans | Complete guide — workflows, features, deployment |
119
+ | `COURSE_AUTHORING_GUIDE.md` | AI Agents | Slide authoring, interactions, CSS styling |
120
+ | `COURSE_OUTLINE_GUIDE.md` | AI Agents | How to write effective course outlines |
121
+ | `COURSE_OUTLINE_TEMPLATE.md` | AI Agents | Blank template to start an outline |
122
+ | `FRAMEWORK_GUIDE.md` | AI Agents | Framework internals (advanced) |
123
+
124
+ ---
125
+
126
+ ## AI-Driven Authoring Workflow
127
+
128
+ Four steps to go from source materials to a deployed course.
129
+
130
+ ### Step 1: Convert Your Source Materials
131
+
132
+ Place existing content (PDFs, Word docs, PowerPoints) in `course/references/`, then run:
133
+
134
+ ```bash
135
+ coursecode convert
136
+ ```
137
+
138
+ Converts to markdown in `course/references/converted/`. Skip this step if starting from scratch.
139
+
140
+ ### Step 2: Create Your Course Outline
141
+
142
+ Ask your AI to create a course outline based on your content.
143
+
144
+ - **With MCP**: The AI reads your references and outline template automatically
145
+ - **Without MCP**: Share your converted docs, `COURSE_OUTLINE_TEMPLATE.md`, and `COURSE_OUTLINE_GUIDE.md` with your AI
146
+
147
+ Review and refine the outline before building.
148
+
149
+ ### Step 3: Build the Course
150
+
151
+ Ask your AI to build slides from your approved outline.
152
+
153
+ - **With MCP**: The AI reads all docs, lints its code, and screenshots slides to verify
154
+ - **Without MCP**: Share your outline and `COURSE_AUTHORING_GUIDE.md` with your AI
155
+
156
+ ### Step 4: Preview, Iterate, and Deploy
157
+
158
+ ```bash
159
+ coursecode preview
160
+ ```
161
+
162
+ The preview server provides:
163
+ - **Live reload**: Changes appear instantly
164
+ - **Visual editing**: Click elements to edit content directly
165
+ - **Status dashboard**: Course health, errors, and build status at a glance
166
+ - **Config panels**: Adjust settings, interactions, and assessments
167
+ - **Component catalog**: Browse available UI elements with live previews
168
+ - **Debug tools**: Inspect LMS state, test interactions, verify tracking
169
+
170
+ When ready, build and deploy:
171
+
172
+ ```bash
173
+ coursecode build
174
+ ```
175
+
176
+ This creates a ZIP package ready for upload to any LMS.
177
+
178
+ **Share for review:** Export a standalone preview for stakeholders:
179
+
180
+ ```bash
181
+ coursecode preview --export
182
+ ```
183
+
184
+ Deploy to GitHub Pages, Netlify, or any static host. Optional password protection keeps content secure.
185
+
186
+ ---
187
+
188
+ ## CLI Commands
189
+
190
+ | Command | Description |
191
+ |---------|-------------|
192
+ | `coursecode create <name>` | Create a new course project |
193
+ | `coursecode preview` | Preview your course locally |
194
+ | `coursecode build` | Build course package (ZIP for LMS upload) |
195
+ | `coursecode build --format scorm1.2` | Build for specific LMS format |
196
+ | `coursecode mcp` | Start the MCP server for AI integration |
197
+ | `coursecode narration` | Generate audio narration from text |
198
+ | `coursecode convert` | Convert PDFs, Word, PowerPoint to markdown |
199
+ | `coursecode upgrade` | Upgrade to latest version |
200
+
201
+ ### Output Format Options
202
+
203
+ ```bash
204
+ coursecode build --format cmi5 # cmi5/xAPI (default, recommended)
205
+ coursecode build --format scorm2004 # SCORM 2004 4th Edition
206
+ coursecode build --format scorm1.2 # SCORM 1.2 (widest LMS support)
207
+ coursecode build --format lti # LTI 1.3
208
+ ```
209
+
210
+ ---
211
+
212
+ ## UI Components
213
+
214
+ Build engaging slides with interactive elements. No coding required — your AI assistant handles the implementation.
215
+
216
+ ### Media & Widgets
217
+
218
+ | Component | Description |
219
+ |-----------|-------------|
220
+ | Tabs | Switch between content panels |
221
+ | Accordion | Expandable/collapsible sections |
222
+ | Flip Cards | Reveal content on click |
223
+ | Carousel | Swipe through slides |
224
+ | Modal | Pop-up detail views |
225
+ | Interactive Timeline | Clickable timeline events |
226
+ | Interactive Image | Hotspots on images |
227
+ | Embed Frame | Sandboxed HTML/JS content |
228
+ | Audio Player | Narration with controls |
229
+ | Video Player | Native, YouTube, or Vimeo |
230
+
231
+ ### Slide Templates
232
+
233
+ Pre-designed layouts for common slide types. Just tell your AI assistant what you need.
234
+
235
+ | Template | Use Case |
236
+ |----------|----------|
237
+ | Intro Cards | Overview slide with key points below |
238
+ | Steps | Sequential instructions (numbered) |
239
+ | Features | Highlight 3-4 key capabilities |
240
+ | Comparison | Side-by-side options |
241
+ | Stats | Metrics and numbers with impact |
242
+ | Content + Image | Text alongside diagrams |
243
+ | Hero | Full-width intro with call-to-action |
244
+ | Timeline | Chronological events |
245
+ | Quote | Testimonials and citations |
246
+ | Checklist | Task lists and requirements |
247
+
248
+ ---
249
+
250
+ ## Interaction Types
251
+
252
+ Practice activities that engage learners and check understanding.
253
+
254
+ | Type | Description |
255
+ |------|-------------|
256
+ | Multiple Choice | Select one or more correct answers |
257
+ | True/False | Simple yes/no questions |
258
+ | Fill-in-the-Blank | Enter missing text (supports typo tolerance) |
259
+ | Matching | Connect related items |
260
+ | Drag-and-Drop | Sort items into categories |
261
+ | Sequencing | Arrange items in correct order |
262
+ | Numeric | Enter numbers (exact or range) |
263
+ | Hotspot | Click correct areas on an image |
264
+ | Likert Scale | Rating scales for surveys |
265
+
266
+ All interactions provide immediate feedback and can be required for slide completion.
267
+
268
+ ---
269
+
270
+ ## Tracking & Scoring
271
+
272
+ ### Engagement
273
+
274
+ Require learners to complete activities before advancing:
275
+ - View all tabs or accordion panels
276
+ - Complete interactions
277
+ - Watch video or listen to audio
278
+ - Spend minimum time on slide
279
+
280
+ ### Gating
281
+
282
+ Lock slides until conditions are met:
283
+ - Complete previous slides
284
+ - Pass an assessment
285
+ - Achieve a learning objective
286
+
287
+ ### Assessments
288
+
289
+ Graded quizzes that determine course completion:
290
+ - Randomized question order
291
+ - Question banks for variety
292
+ - Configurable passing scores
293
+ - Retry attempts with remediation
294
+ - Scores reported to your LMS
295
+
296
+ ### Learning Objectives
297
+
298
+ Track learner progress against defined goals:
299
+ - Automatic: track when slides are visited
300
+ - Linked: tie objectives to assessment scores
301
+ - Reported: completion status sent to LMS
302
+
303
+ ---
304
+
305
+ ## Learn More
306
+
307
+ The [User Guide](framework/docs/USER_GUIDE.md) covers everything in detail:
308
+
309
+ - Using the preview and visual editing tools
310
+ - All interaction types (multiple choice, drag-drop, matching, and more)
311
+ - Assessments and grading
312
+ - Audio and video
313
+ - Theming and branding
314
+ - Navigation and learner flow control
315
+ - Deployment options
316
+ - Troubleshooting
317
+
318
+ ---
319
+
320
+ ## License
321
+
322
+ MIT © Seth Vincent
@@ -0,0 +1,22 @@
1
+ # Third-Party Notices
2
+
3
+ This project includes third-party components and standards artifacts.
4
+
5
+ ## pipwerks SCORM Wrapper
6
+
7
+ - Path: `framework/js/vendor/pipwerks.js`
8
+ - Upstream: https://github.com/pipwerks/scorm-api-wrapper
9
+ - License: MIT-style (as stated in the file header)
10
+
11
+ ## IEEE LOM / SCORM Schema Files
12
+
13
+ - Path: `schemas/` and `schemas/common/`
14
+ - Notes: Several schema files include embedded attribution text referencing
15
+ Creative Commons Attribution-ShareAlike.
16
+ - Local license reference file: `schemas/license.txt`
17
+ - License URL: https://creativecommons.org/licenses/by-sa/1.0/legalcode
18
+
19
+ ## Project License
20
+
21
+ - This project’s primary license is MIT.
22
+ - See: `LICENSE`
package/bin/cli.js ADDED
@@ -0,0 +1,331 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * CourseCode CLI
5
+ *
6
+ * Commands:
7
+ * coursecode create <name> - Create a new course project
8
+ * coursecode dev - Start development server
9
+ * coursecode build - Build course package
10
+ * coursecode upgrade - Upgrade framework in current project
11
+ * coursecode clean - Remove example files from project
12
+ * coursecode new <type> - Create new slide, assessment, or config
13
+ * coursecode test-errors - Test error reporting configuration
14
+ * coursecode test-data - Test data reporting configuration
15
+ * coursecode --version - Show version
16
+ */
17
+
18
+ import { Command } from 'commander';
19
+ import { fileURLToPath } from 'url';
20
+ import path from 'path';
21
+ import fs from 'fs';
22
+
23
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
24
+ const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
25
+
26
+ const program = new Command();
27
+
28
+ program
29
+ .name('coursecode')
30
+ .description('Multi-format course authoring framework CLI')
31
+ .version(packageJson.version);
32
+
33
+ // Create command
34
+ program
35
+ .command('create <name>')
36
+ .description('Create a new course project')
37
+ .option('--blank', 'Create without example slides (clean starter)')
38
+ .option('--no-install', 'Skip npm install')
39
+ .action(async (name, options) => {
40
+ const { create } = await import('../lib/create.js');
41
+ await create(name, options);
42
+ });
43
+
44
+ // Dev command
45
+ program
46
+ .command('dev')
47
+ .description('Start development server with hot reload')
48
+ .option('-p, --port <port>', 'Port to run on', '5173')
49
+ .option('-f, --format <format>', 'LMS format: scorm2004, scorm1.2, cmi5, lti, scorm1.2-proxy, scorm2004-proxy, or cmi5-remote')
50
+ .action(async (options) => {
51
+ const { dev } = await import('../lib/dev.js');
52
+ await dev(options);
53
+ });
54
+
55
+ // Build command
56
+ program
57
+ .command('build')
58
+ .description('Build course package for LMS deployment')
59
+ .option('--no-zip', 'Skip ZIP archive creation')
60
+ .option('--no-lint', 'Skip linting')
61
+ .option('-f, --format <format>', 'LMS format: scorm2004, scorm1.2, cmi5, lti, scorm1.2-proxy, scorm2004-proxy, or cmi5-remote')
62
+ .action(async (options) => {
63
+ const { build } = await import('../lib/build.js');
64
+ await build(options);
65
+ });
66
+
67
+ // Lint command
68
+ program
69
+ .command('lint')
70
+ .description('Validate course configuration and structure')
71
+ .option('--course-path <path>', 'Path to course directory (default: ./course)', './course')
72
+ .option('-v, --verbose', 'Show detailed error output')
73
+ .action(async (options) => {
74
+ const { lint } = await import('../lib/build-linter.js');
75
+ await lint(options);
76
+ });
77
+
78
+ // Upgrade command
79
+ program
80
+ .command('upgrade')
81
+ .description('Upgrade framework in current project to latest version')
82
+ .option('-f, --force', 'Force upgrade even if versions match')
83
+ .option('-c, --configs', 'Also update vite.config.js and eslint.config.js (creates backups)')
84
+ .option('--dry-run', 'Show what would be changed without making changes')
85
+ .action(async (options) => {
86
+ const { upgrade } = await import('../lib/upgrade.js');
87
+ await upgrade(options);
88
+ });
89
+
90
+ // Narration command
91
+ program
92
+ .command('narration')
93
+ .description('Generate audio narration from text using ElevenLabs')
94
+ .option('-f, --force', 'Regenerate all narration (ignore cache)')
95
+ .option('-s, --slide <id>', 'Generate narration for a specific slide only')
96
+ .option('--dry-run', 'Preview what would be generated')
97
+ .action(async (options) => {
98
+ const { narration } = await import('../lib/narration.js');
99
+ await narration(options);
100
+ });
101
+
102
+ // Export content command
103
+ program
104
+ .command('export-content')
105
+ .description('Export course content to Markdown or JSON for review/localization. Extracts: headers, tabs, accordions, callouts, cards, flip-cards, tables, pattern layouts, and all interaction types.')
106
+ .option('-o, --output <file>', 'Output file path (defaults to stdout)')
107
+ .option('--no-answers', 'Exclude correct answers for interactions (included by default)')
108
+ .option('--no-feedback', 'Exclude feedback text (included by default)')
109
+ .option('--no-interactions', 'Exclude interactions and assessment questions from output')
110
+ .option('--include-narration', 'Include narration transcripts')
111
+ .option('--interactions-only', 'Export only interactions and assessment questions (no slide content)')
112
+ .option('--slides <ids>', 'Comma-separated slide IDs to export')
113
+ .option('--format <type>', 'Output format: md or json (default: md)', 'md')
114
+ .option('--course-path <path>', 'Path to course directory (default: ./course)', './course')
115
+ .option('--include-anchors', 'Include HTML anchor tags for internal linking (used by preview content viewer)')
116
+ .action(async (options) => {
117
+ const { exportContent } = await import('../lib/export-content.js');
118
+ // Commander uses --no-X pattern: answers defaults to true, --no-answers sets it to false
119
+ const exportOptions = {
120
+ ...options,
121
+ includeAnswers: options.answers !== false,
122
+ includeFeedback: options.feedback !== false,
123
+ excludeInteractions: options.interactions === false,
124
+ includeAnchors: options.includeAnchors === true ? true : undefined,
125
+ };
126
+ await exportContent(exportOptions);
127
+ });
128
+
129
+ // Convert command
130
+ program
131
+ .command('convert [source]')
132
+ .description('Convert docx, pptx, and pdf files to markdown for course authoring')
133
+ .option('-o, --output <dir>', 'Output directory for converted files', './course/references/converted')
134
+ .option('-f, --format <type>', 'Limit to format: docx, pptx, pdf, or all', 'all')
135
+ .option('--dry-run', 'Show what would be converted without writing files')
136
+ .option('--overwrite', 'Overwrite existing markdown files')
137
+ .option('--flatten', 'Output all files to single directory (no subdirs)')
138
+ .action(async (source = './course/references', options) => {
139
+ const { convert } = await import('../lib/convert.js');
140
+ await convert(source, options);
141
+ });
142
+
143
+ // Import command - PowerPoint to presentation course
144
+ program
145
+ .command('import <source>')
146
+ .description('Import a PowerPoint file as a presentation course')
147
+ .option('-n, --name <name>', 'Project name (default: derived from filename)')
148
+ .option('--slides-dir <dir>', 'Use pre-exported slide images from this directory (skips PowerPoint)')
149
+ .option('--no-install', 'Skip npm install')
150
+ .action(async (source, options) => {
151
+ const { importPresentation } = await import('../lib/import.js');
152
+ await importPresentation(source, options);
153
+ });
154
+
155
+ // Preview command - live preview with stub LMS, or export static preview
156
+ program
157
+ .command('preview')
158
+ .description('Live preview with stub LMS + auto-rebuild, or export static preview')
159
+ .option('-e, --export', 'Export static preview folder for sharing (instead of live server)')
160
+ .option('-o, --output <dir>', 'Output directory for export (default: ./course-preview)', './course-preview')
161
+ .option('-p, --password <password>', 'Require password to access preview (export only)')
162
+ .option('--title <title>', 'Custom title (default: course title)')
163
+ .option('--port <port>', 'Preview server port (default: 4173)', '4173')
164
+ .option('--skip-build', 'Skip build step for export (use existing dist folder)')
165
+ .option('--nojekyll', 'Add .nojekyll file (required for GitHub Pages)')
166
+ .option('--no-content', 'Exclude course content viewer from preview toolbar')
167
+ .option('-f, --format <format>', 'LMS format: scorm2004, scorm1.2, cmi5, lti, scorm1.2-proxy, scorm2004-proxy, or cmi5-remote')
168
+ .option('--desktop', 'Signal that preview is launched via the desktop companion app')
169
+ .action(async (options) => {
170
+ if (options.export) {
171
+ const { previewExport } = await import('../lib/preview-export.js');
172
+ await previewExport(options);
173
+ } else {
174
+ const { previewServer } = await import('../lib/preview-server.js');
175
+ await previewServer(options);
176
+ }
177
+ });
178
+
179
+ // Info command (useful for debugging)
180
+ program
181
+ .command('info')
182
+ .description('Show info about current project')
183
+ .action(async () => {
184
+ const { info } = await import('../lib/info.js');
185
+ await info();
186
+ });
187
+
188
+ // Test error reporting command
189
+ program
190
+ .command('test-errors')
191
+ .description('Send a test error to verify error reporting is configured correctly')
192
+ .option('-t, --type <type>', 'Type of test: error or report', 'error')
193
+ .option('-m, --message <message>', 'Custom message to include in the test')
194
+ .option('--insecure', 'Skip TLS certificate verification (for corporate proxies)')
195
+ .action(async (options) => {
196
+ const { testErrorReporting } = await import('../lib/test-error-reporting.js');
197
+ await testErrorReporting(options);
198
+ });
199
+
200
+ // Test data reporting command
201
+ program
202
+ .command('test-data')
203
+ .description('Send a test data record to verify data reporting is configured correctly')
204
+ .option('-t, --type <type>', 'Type of record: assessment, objective, or interaction', 'assessment')
205
+ .option('-m, --message <message>', 'Custom message to include in the test')
206
+ .option('--insecure', 'Skip TLS certificate verification (for corporate proxies)')
207
+ .action(async (options) => {
208
+ const { testDataReporting } = await import('../lib/test-data-reporting.js');
209
+ await testDataReporting(options);
210
+ });
211
+
212
+ // MCP server command
213
+ program
214
+ .command('mcp')
215
+ .description('Start MCP server for AI agent integration (connects to running preview server)')
216
+ .option('--port <port>', 'Preview server port to connect to', '4173')
217
+ .action(async (options) => {
218
+ const { startMcpServer } = await import('../lib/mcp-server.js');
219
+ await startMcpServer(options);
220
+ });
221
+ // Token generation command
222
+ program
223
+ .command('token')
224
+ .description('Generate access token for multi-tenant CDN deployment')
225
+ .option('--add <clientId>', 'Add client to course-config with generated token')
226
+ .action(async (options) => {
227
+ const { token } = await import('../lib/token.js');
228
+ await token(options);
229
+ });
230
+
231
+ // Clean command - remove example files from project
232
+ program
233
+ .command('clean')
234
+ .description('Remove example slides, audio, and reset course-config.js to minimal starter')
235
+ .action(async () => {
236
+ const { clean } = await import('../lib/scaffold.js');
237
+ clean();
238
+ });
239
+
240
+ // New command - scaffold new files
241
+ const newCmd = program
242
+ .command('new')
243
+ .description('Create new course files (slide, assessment, or config)');
244
+
245
+ newCmd
246
+ .command('slide <id>')
247
+ .description('Create a new slide file in course/slides/')
248
+ .action(async (id) => {
249
+ const { newSlide } = await import('../lib/scaffold.js');
250
+ newSlide(id);
251
+ });
252
+
253
+ newCmd
254
+ .command('assessment <id>')
255
+ .description('Create a new assessment file in course/slides/')
256
+ .action(async (id) => {
257
+ const { newAssessment } = await import('../lib/scaffold.js');
258
+ newAssessment(id);
259
+ });
260
+
261
+ newCmd
262
+ .command('config')
263
+ .description('Create a minimal course-config.js (errors if one exists)')
264
+ .action(async () => {
265
+ const { newConfig } = await import('../lib/scaffold.js');
266
+ newConfig();
267
+ });
268
+
269
+ // Cloud commands — all support --local to target http://localhost:3000
270
+ program
271
+ .command('login')
272
+ .description('Log in to CourseCode Cloud')
273
+ .option('--local', 'Use local Cloud instance (http://localhost:3000)')
274
+ .action(async (options) => {
275
+ const { login, setLocalMode } = await import('../lib/cloud.js');
276
+ if (options.local) setLocalMode();
277
+ await login();
278
+ });
279
+
280
+ program
281
+ .command('logout')
282
+ .description('Log out of CourseCode Cloud')
283
+ .action(async () => {
284
+ const { logout } = await import('../lib/cloud.js');
285
+ await logout();
286
+ });
287
+
288
+ program
289
+ .command('whoami')
290
+ .description('Show current Cloud user and organizations')
291
+ .option('--local', 'Use local Cloud instance (http://localhost:3000)')
292
+ .option('--json', 'Output raw JSON')
293
+ .action(async (options) => {
294
+ const { whoami, setLocalMode } = await import('../lib/cloud.js');
295
+ if (options.local) setLocalMode();
296
+ await whoami({ json: options.json });
297
+ });
298
+
299
+ program
300
+ .command('courses')
301
+ .description('List courses on CourseCode Cloud')
302
+ .option('--local', 'Use local Cloud instance (http://localhost:3000)')
303
+ .action(async (options) => {
304
+ const { listCourses, setLocalMode } = await import('../lib/cloud.js');
305
+ if (options.local) setLocalMode();
306
+ await listCourses();
307
+ });
308
+
309
+ program
310
+ .command('deploy')
311
+ .description('Build and deploy course to CourseCode Cloud')
312
+ .option('--preview', 'Deploy as preview (expires in 7 days)')
313
+ .option('--password', 'Password-protect preview (interactive prompt)')
314
+ .option('--local', 'Use local Cloud instance (http://localhost:3000)')
315
+ .action(async (options) => {
316
+ const { deploy, setLocalMode } = await import('../lib/cloud.js');
317
+ if (options.local) setLocalMode();
318
+ await deploy(options);
319
+ });
320
+
321
+ program
322
+ .command('status')
323
+ .description('Show deployment status for current course')
324
+ .option('--local', 'Use local Cloud instance (http://localhost:3000)')
325
+ .action(async (options) => {
326
+ const { status, setLocalMode } = await import('../lib/cloud.js');
327
+ if (options.local) setLocalMode();
328
+ await status();
329
+ });
330
+
331
+ program.parse();