ronin-skillforce 0.1.0 → 0.2.0-beta.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 (155) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/LICENSE +202 -21
  3. package/NOTICE +19 -0
  4. package/README.md +38 -5
  5. package/bin/cli.js +15 -3
  6. package/bin/commands/archive.js +192 -0
  7. package/bin/commands/capstone-status.js +82 -0
  8. package/bin/commands/create.js +69 -12
  9. package/bin/commands/import.js +5 -5
  10. package/bin/commands/status.js +1 -1
  11. package/bin/commands/studio-autostart.js +414 -0
  12. package/bin/commands/studio-state.js +159 -0
  13. package/bin/commands/studio.js +351 -17
  14. package/bin/commands/trail.js +153 -3
  15. package/bin/commands/web.js +8 -10
  16. package/bin/course-reader.js +6 -15
  17. package/bin/platforms/_shared.js +154 -28
  18. package/bin/platforms/claude.js +23 -42
  19. package/bin/platforms/cursor.js +23 -20
  20. package/bin/platforms/gemini.js +18 -19
  21. package/bin/platforms/opencode.js +47 -28
  22. package/package.json +5 -4
  23. package/plugin.json +1 -1
  24. package/shared/SKILL.md +102 -72
  25. package/shared/agents/coach.md +19 -16
  26. package/shared/agents/navigator.md +27 -34
  27. package/shared/agents/professor.md +16 -34
  28. package/shared/agents/researcher.md +1 -1
  29. package/shared/agents/spotter.md +3 -4
  30. package/shared/commands/professor/archive.md +65 -72
  31. package/shared/commands/professor/capstone-review.md +5 -5
  32. package/shared/commands/professor/capstone.md +3 -3
  33. package/shared/commands/professor/done.md +59 -31
  34. package/shared/commands/professor/hint.md +14 -2
  35. package/shared/commands/professor/navigator.md +27 -1
  36. package/shared/commands/professor/new-topic.md +3 -3
  37. package/shared/commands/professor/next.md +9 -5
  38. package/shared/commands/professor/note.md +6 -6
  39. package/shared/commands/professor/progress.md +1 -1
  40. package/shared/commands/professor/publish.md +5 -5
  41. package/shared/commands/professor/quiz.md +2 -2
  42. package/shared/commands/professor/recall.md +1 -1
  43. package/shared/commands/professor/review.md +14 -0
  44. package/shared/commands/professor/skill-export.md +3 -4
  45. package/shared/commands/professor/spotter.md +21 -4
  46. package/shared/commands/professor/stuck.md +24 -0
  47. package/shared/commands/professor/switch.md +1 -1
  48. package/shared/commands/professor/syllabus.md +1 -1
  49. package/shared/commands/professor/template-export.md +2 -2
  50. package/shared/commands/professor/worktrees.md +3 -7
  51. package/shared/hooks/pre-compact.js +4 -15
  52. package/studio/dist/assets/BetaReportPanel-BJ9HIAnz.js +1 -0
  53. package/studio/dist/assets/{Capstone-Cv9kH6LY.js → Capstone-CoUU-jP7.js} +1 -1
  54. package/studio/dist/assets/{CodeWorkspace-BwCEINWo.js → CodeWorkspace-BNrL4qvR.js} +2 -2
  55. package/studio/dist/assets/{Course-BJ_hafUP.js → Course-BMGTXus_.js} +1 -1
  56. package/studio/dist/assets/{Editor-CV0mNhlz.js → Editor-Cw9j3cnp.js} +1 -1
  57. package/studio/dist/assets/{Home-C1ry89ak.js → Home-D2woITq5.js} +1 -1
  58. package/studio/dist/assets/{Lesson-2e9TD9yL.js → Lesson-CYQhrDCZ.js} +2 -2
  59. package/studio/dist/assets/{NewCourse-BZeOg2xn.js → NewCourse-CMpwVRQb.js} +1 -1
  60. package/studio/dist/assets/{Progress-CRc_xEWC.js → Progress-2rS19Fur.js} +1 -1
  61. package/studio/dist/assets/{Review-6QEbHEfk.js → Review-SlqK-hjp.js} +1 -1
  62. package/studio/dist/assets/{Settings-NFnqVQui.js → Settings-t42u7n9H.js} +1 -1
  63. package/studio/dist/assets/{TutorPanel-DXQ6Z3BY.js → TutorPanel-DQDWIU7f.js} +3 -3
  64. package/studio/dist/assets/{abnfDiagram-WEYOIA3C-qeSjKlGM.js → abnfDiagram-WEYOIA3C-jTUmGBuB.js} +1 -1
  65. package/studio/dist/assets/{anthropic-D7NiQCUH.js → anthropic-iIm2l85r.js} +3 -3
  66. package/studio/dist/assets/{architecture-WOLXFQ4H-COG-m35l.js → architecture-WOLXFQ4H-Ch9Ld_vv.js} +1 -1
  67. package/studio/dist/assets/{architectureDiagram-ZHVYKT53-VO7uKoeD.js → architectureDiagram-ZHVYKT53-Dy-z6wsy.js} +1 -1
  68. package/studio/dist/assets/{blockDiagram-RJAE7QA3-BGJF_qiL.js → blockDiagram-RJAE7QA3-2fHVrc6N.js} +1 -1
  69. package/studio/dist/assets/{bridge-BTh0AeNX.js → bridge-Cr0q4rLp.js} +1 -1
  70. package/studio/dist/assets/{c4Diagram-XDPPPE54-C-S10RgU.js → c4Diagram-XDPPPE54-BuuKlG4V.js} +1 -1
  71. package/studio/dist/assets/{capstone-Amn6Hztq.js → capstone-DhwBeNqk.js} +1 -1
  72. package/studio/dist/assets/{card-store-BrbrtX9w.js → card-store-CVMBc-Pv.js} +1 -1
  73. package/studio/dist/assets/channel-M_JkdHrL.js +1 -0
  74. package/studio/dist/assets/{chunk-2E7WHVMD-fv-iqTyC.js → chunk-2E7WHVMD-lZdQWttk.js} +1 -1
  75. package/studio/dist/assets/{chunk-4EMNKR2T-CY9IZrgv.js → chunk-4EMNKR2T-C6kbMwke.js} +1 -1
  76. package/studio/dist/assets/{chunk-55XCU76K-DyTZz7v_.js → chunk-55XCU76K-rkBzkZog.js} +1 -1
  77. package/studio/dist/assets/{chunk-7S6XSTFO-BNMzTLRW.js → chunk-7S6XSTFO-Skg347QF.js} +1 -1
  78. package/studio/dist/assets/{chunk-AQDTSKZB-CEYANohH.js → chunk-AQDTSKZB-0pSDBJ23.js} +1 -1
  79. package/studio/dist/assets/{chunk-DSNLSHJZ-CDk5EXjH.js → chunk-DSNLSHJZ-BaeQDl2i.js} +1 -1
  80. package/studio/dist/assets/{chunk-HAGFOTED-hNAi1zh_.js → chunk-HAGFOTED-BEm00juw.js} +1 -1
  81. package/studio/dist/assets/{chunk-HNE4Q36P-COJnSYoZ.js → chunk-HNE4Q36P-DyCR-LvS.js} +1 -1
  82. package/studio/dist/assets/{chunk-NQOKRVIF-BU6KVxRr.js → chunk-NQOKRVIF-BNJ9uMmB.js} +1 -1
  83. package/studio/dist/assets/{chunk-UHW7PFBP-DYvxL9JG.js → chunk-UHW7PFBP-DqJczBLs.js} +1 -1
  84. package/studio/dist/assets/{chunk-VQ5W62QI-CuRfk65j.js → chunk-VQ5W62QI-CVWYSP5Q.js} +1 -1
  85. package/studio/dist/assets/{chunk-WQQL4CDK-KaG7x-Mb.js → chunk-WQQL4CDK-DJf0Dx05.js} +1 -1
  86. package/studio/dist/assets/{chunk-YZO67HFG-DbuqIZmk.js → chunk-YZO67HFG-BFUm_JHA.js} +1 -1
  87. package/studio/dist/assets/{chunk-ZAUX2LTX-bk4ivUmc.js → chunk-ZAUX2LTX-C5ETkkSE.js} +1 -1
  88. package/studio/dist/assets/{chunk-ZCHMQSOR-B_LElfwh.js → chunk-ZCHMQSOR-WVX9r9PZ.js} +1 -1
  89. package/studio/dist/assets/{classDiagram-v2-4MYWR3UA-DtCJ6H_X.js → classDiagram-v2-4MYWR3UA-CI77SpuR.js} +1 -1
  90. package/studio/dist/assets/{course-export-DpaOTT3a.js → course-export-C8jSPuda.js} +1 -1
  91. package/studio/dist/assets/{cynefin-EF2NZ3EQ-D9btHJvU.js → cynefin-EF2NZ3EQ-CLffmM25.js} +1 -1
  92. package/studio/dist/assets/{cynefinDiagram-WF24UDRP-CsFJuv27.js → cynefinDiagram-WF24UDRP-BvLwocOb.js} +1 -1
  93. package/studio/dist/assets/{dagre-NK4GIZVX-Cg1Duec7.js → dagre-NK4GIZVX-C2nMAVdh.js} +1 -1
  94. package/studio/dist/assets/{diagram-CBK3MWTC-_KU2m5gd.js → diagram-CBK3MWTC-Bid-pdax.js} +1 -1
  95. package/studio/dist/assets/{diagram-I5XIIV2D-5RaBrwUA.js → diagram-I5XIIV2D-DYJeAvzl.js} +1 -1
  96. package/studio/dist/assets/{diagram-ODIL2UCW-C0VKxoD3.js → diagram-ODIL2UCW-B06X2r_F.js} +1 -1
  97. package/studio/dist/assets/{diagram-PFBEJUXE-BaHcZEP2.js → diagram-PFBEJUXE-CwY--5Rz.js} +1 -1
  98. package/studio/dist/assets/{diagram-RJA3I4VV-cwSAZ90p.js → diagram-RJA3I4VV-4SqhH8zw.js} +1 -1
  99. package/studio/dist/assets/{diagram-TYUNFSNR-BJImxCEN.js → diagram-TYUNFSNR-CrW4AIM9.js} +1 -1
  100. package/studio/dist/assets/{ebnfDiagram-V4P3TTPT-OQQLRXcm.js → ebnfDiagram-V4P3TTPT-xeoCmH-d.js} +1 -1
  101. package/studio/dist/assets/{elk-QONTBCTQ-BJGhQHxQ.js → elk-QONTBCTQ-Dadmz6iS.js} +1 -1
  102. package/studio/dist/assets/{erDiagram-KYQIGQAA-D91EKSep.js → erDiagram-KYQIGQAA-CSuH0bbF.js} +1 -1
  103. package/studio/dist/assets/{eventmodeling-K75KTNOO-DgdTRgnw.js → eventmodeling-K75KTNOO-CciVfx3I.js} +1 -1
  104. package/studio/dist/assets/flowDiagram-IUGLLWBU-DgNR54qK.js +1 -0
  105. package/studio/dist/assets/{ganttDiagram-R7GPNTJY-CSYLPWEI.js → ganttDiagram-R7GPNTJY-C0wtA-2y.js} +1 -1
  106. package/studio/dist/assets/{gitGraph-VSP46ZUC-D6GWaV9y.js → gitGraph-VSP46ZUC-BXoDzaA3.js} +1 -1
  107. package/studio/dist/assets/{gitGraphDiagram-PDYL7XHY-CaV31bvT.js → gitGraphDiagram-PDYL7XHY-vZBlNRPe.js} +1 -1
  108. package/studio/dist/assets/{index-DioXTZVc.js → index-CS8XPYbB.js} +2 -2
  109. package/studio/dist/assets/{info-OHQRW6UA-BN-x8GoN.js → info-OHQRW6UA-bs2Qpf7P.js} +1 -1
  110. package/studio/dist/assets/{infoDiagram-MVDRKAX5-CIose_cy.js → infoDiagram-MVDRKAX5-rPJio6-1.js} +1 -1
  111. package/studio/dist/assets/{ishikawaDiagram-HPEHV2GE-DCihSNBw.js → ishikawaDiagram-HPEHV2GE-CXf9XFff.js} +1 -1
  112. package/studio/dist/assets/{journeyDiagram-BOSHW7O7-Bz3o3RIX.js → journeyDiagram-BOSHW7O7-C3MSH79o.js} +1 -1
  113. package/studio/dist/assets/{kanban-definition-FNSA4HC5-BUyqvlFE.js → kanban-definition-FNSA4HC5-Bdh7SB4n.js} +1 -1
  114. package/studio/dist/assets/{line-B08T8KlK.js → line-CHkoQXJF.js} +1 -1
  115. package/studio/dist/assets/{mermaid-parser.core-BYwreSUy.js → mermaid-parser.core-Do1oxD1S.js} +3 -3
  116. package/studio/dist/assets/{mermaid.core-DTO1oDmq.js → mermaid.core-DgZUD0sU.js} +4 -4
  117. package/studio/dist/assets/{mindmap-definition-6OY57UG3-BGLwKheY.js → mindmap-definition-6OY57UG3-PUaK6oE_.js} +1 -1
  118. package/studio/dist/assets/{node.browser-BISniYn8.js → node.browser-DkpMze_r.js} +1 -1
  119. package/studio/dist/assets/{ollama-De5w84tG.js → ollama-bJNp3jaD.js} +1 -1
  120. package/studio/dist/assets/{openai-compatible-Joy1oK3L.js → openai-compatible-0tmAyMlN.js} +1 -1
  121. package/studio/dist/assets/{packet-JDAUHWVQ-CDIMjHS_.js → packet-JDAUHWVQ-vf2FtqFr.js} +1 -1
  122. package/studio/dist/assets/{pegDiagram-ECIUJNBX-DWXm4mwS.js → pegDiagram-ECIUJNBX-NEVrgPTY.js} +1 -1
  123. package/studio/dist/assets/{pie-XZMESJXO-CY3QQiKZ.js → pie-XZMESJXO-BIWydVNZ.js} +1 -1
  124. package/studio/dist/assets/{pieDiagram-GNMPY74T-M1aCnI7W.js → pieDiagram-GNMPY74T-BI9_u6rT.js} +1 -1
  125. package/studio/dist/assets/{quadrantDiagram-D57K4MC3-BFFtO7U5.js → quadrantDiagram-D57K4MC3-ryNpoBC5.js} +1 -1
  126. package/studio/dist/assets/{radar-ABXABTNO-DT0W4_Xn.js → radar-ABXABTNO-D8TjnvBB.js} +1 -1
  127. package/studio/dist/assets/{railroad-I3PHUGI6-_VCpgZR5.js → railroad-I3PHUGI6-BmEDV5kf.js} +1 -1
  128. package/studio/dist/assets/{railroad-abnf-LNEFI6M7-DkSpQ5YY.js → railroad-abnf-LNEFI6M7-Cs_sArMc.js} +1 -1
  129. package/studio/dist/assets/{railroad-ebnf-DWYD2UWJ-BqWILdGb.js → railroad-ebnf-DWYD2UWJ-DYuCq46d.js} +1 -1
  130. package/studio/dist/assets/{railroad-peg-JR7BVNR7-BB0bQL-Z.js → railroad-peg-JR7BVNR7-BcXSgdMy.js} +1 -1
  131. package/studio/dist/assets/{railroadDiagram-Y72NRBL7-CjLKjIdJ.js → railroadDiagram-Y72NRBL7-DBcc8b2c.js} +1 -1
  132. package/studio/dist/assets/{rehype-katex-C-sKddsH.js → rehype-katex-BfUIq5As.js} +1 -1
  133. package/studio/dist/assets/{remark-math-C-ox67hE.js → remark-math-XvZOjmDO.js} +1 -1
  134. package/studio/dist/assets/{requirementDiagram-EQYSW5RA-CnwzZqR8.js → requirementDiagram-EQYSW5RA-CVcBgM1L.js} +1 -1
  135. package/studio/dist/assets/{sankeyDiagram-SY24JHO5-CPDugTUl.js → sankeyDiagram-SY24JHO5-DjZ81hDs.js} +1 -1
  136. package/studio/dist/assets/{sequenceDiagram-BLEHNHQU-1dLfeU9Y.js → sequenceDiagram-BLEHNHQU-BNwOa2S7.js} +1 -1
  137. package/studio/dist/assets/{stateDiagram-v2-A6IESKWZ-DR7CmEjj.js → stateDiagram-v2-A6IESKWZ-BFWa5lEx.js} +1 -1
  138. package/studio/dist/assets/{swimlanes-B3ENRKFQ-BAWB9omQ.js → swimlanes-B3ENRKFQ-LfM_Jg6Z.js} +1 -1
  139. package/studio/dist/assets/swimlanesDiagram-AYQRV4AK-BDmpoiGp.js +8 -0
  140. package/studio/dist/assets/{timeline-definition-JXYKGLGB-DNkj8z77.js → timeline-definition-JXYKGLGB-BwGzkWgZ.js} +1 -1
  141. package/studio/dist/assets/{treeView-D4JQ5SDB-BA-ouhMb.js → treeView-D4JQ5SDB-MLk3VuRt.js} +1 -1
  142. package/studio/dist/assets/{treemap-SAJKECNS-BrrGxsAb.js → treemap-SAJKECNS-D8iSjp7L.js} +1 -1
  143. package/studio/dist/assets/{usecaseDiagram-WPOLBNNX-BB3D0Dt_.js → usecaseDiagram-WPOLBNNX-BqxpaNlT.js} +1 -1
  144. package/studio/dist/assets/{vennDiagram-Q3Y3IDCW-BrtqtKTE.js → vennDiagram-Q3Y3IDCW-CpeUDMhQ.js} +1 -1
  145. package/studio/dist/assets/{wardley-7MLQ67FV-BKkemDql.js → wardley-7MLQ67FV-tAMbCZAj.js} +1 -1
  146. package/studio/dist/assets/{wardleyDiagram-IVAIDKWA-DFnI3P5z.js → wardleyDiagram-IVAIDKWA-CDJViWzt.js} +1 -1
  147. package/studio/dist/assets/{xychartDiagram-4URNHDU4-Da0DZG_q.js → xychartDiagram-4URNHDU4-CwaQrd3_.js} +1 -1
  148. package/studio/dist/index.html +1 -1
  149. package/templates/claude/plugin.json +1 -1
  150. package/templates/gemini/GEMINI.md +18 -16
  151. package/web/server.js +3 -3
  152. package/studio/dist/assets/BetaReportPanel-8NrDLiPm.js +0 -1
  153. package/studio/dist/assets/channel-SJiUQu_N.js +0 -1
  154. package/studio/dist/assets/flowDiagram-IUGLLWBU-CVnJYMum.js +0 -1
  155. package/studio/dist/assets/swimlanesDiagram-AYQRV4AK-qeuHru16.js +0 -8
@@ -3,15 +3,15 @@ name: professor:note
3
3
  description: Save a timestamped note to your course
4
4
  ---
5
5
 
6
- Use `AskUserQuestion` to collect note details, then append to NOTES.md.
6
+ Collect the note details in one turn (`AskUserQuestion`), then append to NOTES.md.
7
7
 
8
8
  ## Step 1: Detect Active Course
9
9
 
10
- 1. Find the active course: check `learning/*/COURSE.md` first, then legacy `courses/*/COURSE.md`
11
- 2. If active course found → use `NOTES.md` in that same course directory (`learning/{slug}/NOTES.md`, or `courses/{slug}/NOTES.md` for a legacy course)
12
- 3. If no active course → use `courses/notes.md` (global fallback)
10
+ 1. Find the active course: check `learning/*/COURSE.md` (the only course location)
11
+ 2. If active course found → use `NOTES.md` in that same course directory (`learning/{slug}/NOTES.md`)
12
+ 3. If no active course → use `learning/notes.md` (global fallback, create `learning/` if needed)
13
13
 
14
- ## Step 2: AskUserQuestion Flow
14
+ ## Step 2: Collect the Note
15
15
 
16
16
  Ask two questions in sequence:
17
17
 
@@ -54,7 +54,7 @@ I should explore async/await patterns...
54
54
 
55
55
  Display:
56
56
  - The saved note with timestamp and type
57
- - File path: "Saved to: learning/{slug}/NOTES.md" (or the legacy `courses/{slug}/NOTES.md`) or "Saved to: courses/notes.md"
57
+ - File path: "Saved to: learning/{slug}/NOTES.md" or "Saved to: learning/notes.md"
58
58
  - "Add another note? Run `/professor:note` anytime."
59
59
 
60
60
  ## Error Handling
@@ -13,7 +13,7 @@ Read `COURSE.md` and produce a structured progress summary including:
13
13
  - Estimated time to finish the course
14
14
  - Capstone project status
15
15
 
16
- Consult the archived lectures in `lectures/NN-<slug>.md` (in `learning/{slug}/` first, then `courses/{slug}/`) and `LEARNING-LOG.md` for detail on completed sections — cite the relevant archive when summarising what a section covered.
16
+ Consult the archived lectures in `lectures/NN-<slug>.md` (in `learning/{slug}/`) and `LEARNING-LOG.md` for detail on completed sections — cite the relevant archive when summarising what a section covered.
17
17
 
18
18
  **Engagement Stats:**
19
19
 
@@ -7,10 +7,9 @@ When user runs `professor:publish`, follow these steps to share your course or s
7
7
 
8
8
  ## Step 1: Find Active Course Directory
9
9
 
10
- Check both worktree and legacy structures:
11
- - If already in `learning/{slug}/` or `courses/{slug}/` directory, use that.
10
+ Check the course structure:
11
+ - If already in `learning/{slug}/` directory, use that.
12
12
  - Otherwise, check for `COURSE.md` in `learning/` subdirectory.
13
- - If not found there, check `courses/` subdirectory (legacy).
14
13
  - If still not found, check for `COURSE.md` in the current working directory.
15
14
  - If no active course is found, respond:
16
15
  > "No active course found. Run `/professor:new-topic` to start a course first."
@@ -18,7 +17,8 @@ Check both worktree and legacy structures:
18
17
 
19
18
  ## Step 2: Multi-Course Disambiguation
20
19
 
21
- If multiple course directories exist in `learning/` (e.g., `learning/react-hooks/` and `learning/sql-auditor/`), ask the user which one to publish using AskUserQuestion:
20
+ If multiple course directories exist in `learning/` (e.g., `learning/react-hooks/` and
21
+ `learning/sql-auditor/`), ask which one to publish (`AskUserQuestion`):
22
22
  > "You have multiple courses. Which would you like to publish?"
23
23
  List all `learning/` directories that contain `COURSE.md`.
24
24
 
@@ -48,7 +48,7 @@ Extract:
48
48
  - **description**: from SKILL.md frontmatter `description` (skills) or COURSE.md
49
49
  - **level**: from COURSE.md frontmatter (Beginner / Intermediate / Advanced / Expert)
50
50
 
51
- Ask the user for any missing required fields using AskUserQuestion:
51
+ Ask for any missing required fields in one turn (`AskUserQuestion`):
52
52
  - **GitHub username**: "What is your GitHub username?"
53
53
  - **description**: "Give a 1-2 sentence description of this [course/skill]."
54
54
  - **topics**: "What topics does this cover?" (comma-separated list)
@@ -4,7 +4,7 @@ description: "Run a quiz on your current topic"
4
4
  argument-hint: "[section or concept]"
5
5
  ---
6
6
 
7
- Use AskUserQuestion to ask the scope before generating questions:
7
+ Ask the scope in one question before generating anything (`AskUserQuestion`):
8
8
  > "What would you like to be quizzed on?"
9
9
 
10
10
  Options: "Current section" / "Entire course so far" / "Specific concept (describe below)"
@@ -17,7 +17,7 @@ After the user answers, review each answer with Socratic feedback — never just
17
17
 
18
18
  **Persist the quiz results:**
19
19
 
20
- Append a quiz entry to `LEARNING-LOG.md` in the course directory (`learning/{slug}/` first, then `courses/{slug}/`; create the file if missing):
20
+ Append a quiz entry to `LEARNING-LOG.md` in the course directory (`learning/{slug}/`; create the file if missing):
21
21
 
22
22
  - **Date** — today
23
23
  - **Scope** — current section / entire course / specific concept
@@ -20,7 +20,7 @@ description: Run an interactive recall session for due sections
20
20
 
21
21
  Read the 3 flashcards from SCHEDULE.md for this section.
22
22
 
23
- If the section's lecture was archived, also read `lectures/NN-<slug>.md` (in `learning/{slug}/` first, then `courses/{slug}/`) to ground the recall questions in the original material and confirm the flashcards still match what was taught.
23
+ If the section's lecture was archived, also read `lectures/NN-<slug>.md` (in `learning/{slug}/`) to ground the recall questions in the original material and confirm the flashcards still match what was taught.
24
24
 
25
25
  **Card 1: Conceptual**
26
26
  > **Reviewing: [Section Name]**
@@ -28,6 +28,20 @@ Delegate to the Coach agent with:
28
28
 
29
29
  Coach will guide the review through self-assessment dialogue.
30
30
 
31
+ ## If no Coach agent is available:
32
+
33
+ > If no Coach agent is available on this platform, run the Coach flow below inline.
34
+
35
+ Run the review yourself, in this order — you are the Coach here:
36
+
37
+ 1. Open with: *"Before I look at your work — what do you think about it? What's working, and what are you unsure about?"* Let their answer shape everything that follows.
38
+ 2. **✅ What's working** — one or two sentences on what they got right.
39
+ 3. **❓ Socratic question** — point at the most important gap with a question, not a correction.
40
+ 4. **💡 One concept to study** — name it; do not explain it fully.
41
+ 5. **⏭️ Next action** — one clear thing to try, then share again.
42
+
43
+ Then record the round with the `trail` step below, exactly as Coach would have. Never rewrite their code, and never answer with a bare "correct" or "wrong".
44
+
31
45
  ## After each review round — record it (required)
32
46
 
33
47
  Coach ends each completed round with a fenced `trail` block (`learner`, `asked`, `concept`, optional `evidence`, `watch`). Record it:
@@ -7,10 +7,9 @@ When user runs `professor:skill-export`, follow these steps to encode your capst
7
7
 
8
8
  ## Step 1: Find Active Course Directory
9
9
 
10
- Check both worktree and legacy structures:
11
- - If already in `learning/{slug}/` or `courses/{slug}/` directory, use that.
10
+ Check the course structure:
11
+ - If already in `learning/{slug}/` directory, use that.
12
12
  - Otherwise, check for `COURSE.md` in `learning/` subdirectory.
13
- - If not found there, check `courses/` subdirectory (legacy).
14
13
  - If still not found, check for `COURSE.md` in the current working directory.
15
14
  - If no active course is found, respond:
16
15
  > "No active course found. Run `/professor:new-topic` to start a course first."
@@ -38,7 +37,7 @@ Extract:
38
37
 
39
38
  ## Step 4: Generate SKILL.md
40
39
 
41
- Write `learning/{slug}/SKILL.md` (or `courses/{slug}/SKILL.md` — same directory as COMPLETION.md) with 50–150 lines:
40
+ Write `learning/{slug}/SKILL.md` (same directory as COMPLETION.md) with 50–150 lines:
42
41
 
43
42
  ```markdown
44
43
  ---
@@ -23,6 +23,12 @@ Run `professor:spotter` whenever:
23
23
 
24
24
  ## Behavior
25
25
 
26
+ ### Step 0: Get the course context
27
+
28
+ Run `npx ronin-skillforce context {slug} --json` before the check-in. It returns the absolute
29
+ `dir`, `section`, `activeExercise`, `watch` flags and recent `trail`. If it exits non-zero, show
30
+ its error and ask the learner which course — never guess a slug or path.
31
+
26
32
  ### Step 1: Present Position Check-in
27
33
 
28
34
  When invoked, Spotter presents the position prompt:
@@ -44,10 +50,10 @@ Based on learner's response:
44
50
  - **(b)** → Ask: "What exactly is the wall? Describe it."
45
51
  - **(c)** → Ask: "What makes you unsure? Walk me through your logic."
46
52
  - **(d)** → Say "Let me hand you off to Coach for review" and invoke Coach
47
-
48
53
  ### Step 3: Append Attempt Log
49
54
 
50
- After each check-in, append an entry to `LEARNING-LOG.md`:
55
+ After each check-in, append an entry to `LEARNING-LOG.md` (Professor is the only writer; the Spotter
56
+ agent returns the line, it never edits the file):
51
57
 
52
58
  ```markdown
53
59
  ## 📋 Attempt Log
@@ -62,7 +68,7 @@ After each check-in, append an entry to `LEARNING-LOG.md`:
62
68
 
63
69
  ## File Paths
64
70
 
65
- - Course: `learning/{slug}/` (worktree) or `courses/{slug}/` (legacy)
71
+ - Course: `learning/{slug}/`
66
72
  - LEARNING-LOG.md: In the course directory alongside COURSE.md
67
73
 
68
74
  ---
@@ -73,4 +79,15 @@ For position (d), Spotter hands off to Coach:
73
79
 
74
80
  > "Let me hand you off to Coach for review. Coach will ask you a self-assessment question first."
75
81
 
76
- Then invoke the Coach agent with `professor:review`.
82
+ Then invoke the Coach agent with `professor:review` and pass the `skillforce context` JSON from
83
+ Step 0 **verbatim**, so Coach uses the real course `dir`, section and trail.
84
+
85
+ ## If no Coach agent is available:
86
+
87
+ > If no Coach agent is available on this platform, run the Coach flow below inline.
88
+
89
+ Skip the hand-off and open the review yourself, exactly as `professor:review` describes:
90
+
91
+ 1. Open with: *"Before I look at your work — what do you think about it? What's working, and what are you unsure about?"*
92
+ 2. Then follow the review structure there: ✅ what's working → ❓ one Socratic question → 💡 one concept to study → ⏭️ one next action.
93
+ 3. Record the round with the `trail` CLI step from `professor:review` (`npx ronin-skillforce trail {slug} --stdin`) so the next session sees it; if it fails, say the round was not recorded.
@@ -8,6 +8,18 @@ argument-hint: "[describe what you're stuck on]"
8
8
 
9
9
  This command routes to the **Coach agent** which provides help through self-assessment dialogue.
10
10
 
11
+ ## Capstone guard — check before routing:
12
+
13
+ `professor:stuck` is refused during the **capstone phase**: when every syllabus section is ✅ Done,
14
+ or when `**Capstone status**` is 🔄 In progress or ✅ Complete. Read `COURSE.md` first, then refuse:
15
+
16
+ > "No `professor:stuck` in the capstone phase — the rules change here: build the project yourself,
17
+ > with no hints and no stuck-coaching. You can run `professor:discuss` to talk a concept through, but
18
+ > I won't touch your code."
19
+
20
+ Stop there and do not route to Coach. A course with at least one ⬜ or 🔄 section and
21
+ `**Capstone status**: 🔒 Locked` (or no status line) is not capstone — continue normally.
22
+
11
23
  ## Before routing to Coach:
12
24
 
13
25
  1. **Get the course context** — run `npx ronin-skillforce context {slug} --json`. If it exits non-zero, show its error and ask the learner which course — never guess a slug or path.
@@ -24,4 +36,16 @@ Delegate to the Coach agent with:
24
36
 
25
37
  Coach will guide through self-assessment to identify the exact blocker, then break into smaller steps.
26
38
 
39
+ ## If no Coach agent is available:
40
+
41
+ > If no Coach agent is available on this platform, run the Coach flow below inline.
42
+
43
+ Run the stuck flow yourself — you are the Coach here:
44
+
45
+ 1. Open with the check-in: *"Walk me through what you've tried so far."*
46
+ 2. Identify the **exact sticking point** — a concept gap, a syntax issue, or a logic error?
47
+ 3. Break the problem into **smaller steps**: *"Let's forget the full solution. Can you just do X first?"*
48
+ 4. Give a **worked analogy** from a different, simpler domain.
49
+ 5. Still no solution — name the next smallest step they can take and stop there.
50
+
27
51
  When Coach returns a `trail` block, record it with `npx ronin-skillforce trail {slug} --stdin` and a quoted `<<'TRAIL_EOF'` heredoc of JSON, exactly as in `professor:review`. If that fails, say "⚠️ This round was not recorded" — never claim it was saved.
@@ -17,7 +17,7 @@ When user runs `professor:switch`, switch context to a different learning course
17
17
  2. **If no argument provided (interactive selection)**:
18
18
  - Scan `learning/` directory for subdirectories containing `COURSE.md`
19
19
  - If only one worktree found: use it automatically
20
- - If multiple worktrees found: Use `AskUserQuestion` to let user choose:
20
+ - If multiple worktrees found: let the user choose (`AskUserQuestion`):
21
21
  > "Which course would you like to switch to?"
22
22
  > Options: List each worktree with topic name and progress
23
23
 
@@ -5,5 +5,5 @@ description: View the full course outline and progress
5
5
 
6
6
  Read and display the full contents of `COURSE.md` for the active course.
7
7
 
8
- If no active course exists (no `courses/` directory or it is empty), respond:
8
+ Look for the active course under `learning/` in the current working directory (`learning/*/COURSE.md`). If no course is found (no `learning/` directory, or it contains no course), respond:
9
9
  > "No active course found. Run `/professor:new-topic` to start your first course."
@@ -10,11 +10,11 @@ When user runs `professor:template-export`, follow these steps:
10
10
 
11
11
  1. **Determine course location:**
12
12
  - Check if in `learning/{slug}/` directory
13
- - If not, check if there's a `learning/` or `courses/` subdirectory with a course
13
+ - If not, check if there's a `learning/` subdirectory with a course
14
14
  - If still not found: check for `COURSE.md` in current directory
15
15
 
16
16
  2. **If no course found:**
17
- - Show error: "Run this command from within a course directory (learning/{slug}/ or courses/{slug}/)"
17
+ - Show error: "Run this command from within a course directory (learning/{slug}/)"
18
18
 
19
19
  ## Step 2: Read Course Files
20
20
 
@@ -9,7 +9,7 @@ When user runs `professor:worktrees`, list all available learning courses.
9
9
 
10
10
  **Steps:**
11
11
 
12
- 1. **Check for learning/ directory** (new worktree courses):
12
+ 1. **Check for learning/ directory** (every course lives here):
13
13
  - If `learning/` directory exists, scan for subdirectories containing `COURSE.md`
14
14
  - For each worktree found, extract:
15
15
  - Tech slug (directory name)
@@ -21,11 +21,7 @@ When user runs `professor:worktrees`, list all available learning courses.
21
21
  - If `.course_archive/` directory exists, scan for archived courses
22
22
  - Display archived courses in a separate section
23
23
 
24
- 3. **Check for legacy courses/** directory:
25
- - If courses/ exists (legacy structure), scan for any remaining courses
26
- - Note: These are the old-style courses not in worktrees
27
-
28
- 4. **Display results**:
24
+ 3. **Display results**:
29
25
 
30
26
  If worktrees found:
31
27
  ```
@@ -50,7 +46,7 @@ When user runs `professor:worktrees`, list all available learning courses.
50
46
  If nothing found:
51
47
  > "No learning worktrees or archived courses found. Start a new course with `professor:new-topic`."
52
48
 
53
- 5. **Handle edge cases**:
49
+ 4. **Handle edge cases**:
54
50
  - If learning/ doesn't exist: show helpful message about creating courses
55
51
  - If worktree contains incomplete data: skip gracefully, log warning
56
52
 
@@ -52,16 +52,13 @@ function displayTokenWarning(tokenCount) {
52
52
  }
53
53
 
54
54
  /**
55
- * Find the most recently modified COURSE.md file
55
+ * Find the most recently modified COURSE.md file under learning/
56
56
  *
57
- * Priority:
58
- * 1. First check learning/ directory (new worktree courses)
59
- * 2. Then check courses/ directory (legacy courses)
60
- * Returns the most recently modified COURSE.md from either location
57
+ * Returns the most recently modified COURSE.md in learning/, or null when
58
+ * there is none.
61
59
  */
62
60
  function findMostRecentCourse() {
63
61
  const learningDir = path.join(process.cwd(), 'learning');
64
- const coursesDir = path.join(process.cwd(), 'courses');
65
62
 
66
63
  let mostRecentFile = null;
67
64
  let mostRecentTime = 0;
@@ -97,16 +94,8 @@ function findMostRecentCourse() {
97
94
  }
98
95
  }
99
96
 
100
- // First check learning/ directory (priority for new worktree courses)
101
97
  scanForCourses(learningDir);
102
98
 
103
- // Then check courses/ directory (legacy fallback)
104
- scanForCourses(coursesDir);
105
-
106
- if (!mostRecentFile) {
107
- console.warn('PreCompact: No courses directory found. Skipping session save.');
108
- }
109
-
110
99
  return mostRecentFile;
111
100
  }
112
101
 
@@ -200,7 +189,7 @@ function autoSaveSession() {
200
189
  const coursePath = findMostRecentCourse();
201
190
 
202
191
  if (!coursePath) {
203
- console.warn('PreCompact: No active course found. Skipping session save.');
192
+ console.warn('PreCompact: No course found under learning/. Skipping session save.');
204
193
  return;
205
194
  }
206
195
 
@@ -0,0 +1 @@
1
+ import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{t}from"./react-B8SKf8RM.js";import{u as n}from"./settings-DhwuyNPU.js";import{At as r,Et as i,J as a,K as o,Lt as s,Rt as c,ct as l,f as u,g as d,nt as f,ot as p,p as m,pt as h,q as g}from"./index-CS8XPYbB.js";import{c as _,d as v,i as y,l as b,n as x,o as S,r as ee,s as C,t as w,u as T}from"./schemas-BOc2YsOP.js";import{t as E}from"./course-export-C8jSPuda.js";var D=e(t(),1),O=864e5,k=/^(\d{4})-(\d{2})-(\d{2})$/;function A(e){if(typeof e!=`string`)return null;let t=k.exec(e);if(!t)return null;let n=Number(t[1]),r=Number(t[2]),i=Number(t[3]);if(r<1||r>12||i<1||i>31)return null;let a=Date.UTC(n,r-1,i),o=new Date(a);return o.getUTCFullYear()!==n||o.getUTCMonth()!==r-1||o.getUTCDate()!==i?null:Math.floor(a/O)}function j(e,t){let n=A(e),r=A(t);return n==null||r==null?null:Math.max(0,n-r)}function te(e){if(A(e?.day)!=null)return e.day;if(e?.created_at){let t=r(e.created_at);if(A(t)!=null)return t}return null}function ne(e){let t=null;for(let n of e){if(t==null){t=n;continue}let e=String(n.created_at??``),r=String(t.created_at??``);(e<r||e===r&&String(n.id??``)<String(t.id??``))&&(t=n)}return t}function re({events:e=[],profile:t=null,now:n=new Date}={}){let a=(e||[]).filter(e=>e&&!e.deleted_at&&i.includes(e.kind)),o={};for(let e of i)o[e]=0;for(let e of a)o[e.kind]+=1;let s=t?.activated_day;if(A(s)==null)return{activation:{activated:!1,firstEventKind:null},generatedAtDayOffset:0,window:{activeDayOffsets:[]},loops:{byKind:o},retention:{week1Active:!1,week2Return:!1,week2MeaningfulDays:0}};let c=new Set,l=new Set,u=!1,d=!1;for(let e of a){let t=te(e);if(t==null)continue;let n=j(t,s);n!=null&&(n<=14&&c.add(n),n>=1&&n<=7&&(u=!0),n>=8&&n<=14&&(d=!0,l.add(t)))}let f=ne(a),p=j(r(n),s)??0;return{activation:{activated:!0,firstEventKind:f?f.kind:null},generatedAtDayOffset:p,window:{activeDayOffsets:[...c].sort((e,t)=>e-t)},loops:{byKind:o},retention:{week1Active:u,week2Return:d,week2MeaningfulDays:l.size}}}var M=/^(bridge|byok):(anthropic|openai|openrouter|groq|lmstudio|ollama|custom|claude|opencode|cursor|gemini|antigravity)$/,N=_(Object.fromEntries(i.map(e=>[e,C().int().nonnegative()]))),P=C().int().nonnegative(),F=_({schemaVersion:S(1),participantId:v(),generatedAtDayOffset:C().int().nonnegative(),app:_({version:b().max(32),storage:w([`indexeddb`,`sqlite`,`memory`,`remote`]),provider:T([x(),b().regex(M)])}),activation:_({activated:y(),firstEventKind:T([x(),w(i)])}),window:_({activeDayOffsets:ee(C().int().min(0).max(14))}),loops:_({byKind:N,revisions:_({quiz:P,tutor:P,workspace:P,capstone:P,explicit:P,inferred:P})}),retention:_({week1Active:y(),week2Return:y(),week2MeaningfulDays:C().int().nonnegative()}),capstone:_({started:y(),submissions:C().int().nonnegative(),externalEvidence:C().int().nonnegative(),verdict:T([x(),w([`course_complete`,`needs_work`])])})});function I(e=[]){let t={quiz:0,tutor:0,workspace:0,capstone:0,explicit:0,inferred:0};for(let n of e||[]){if(!n||n.deleted_at)continue;let e=n.surface;e in t&&(t[e]+=1),(n.link_kind===`explicit`||n.link_kind===`inferred`)&&(t[n.link_kind]+=1)}return t}function L({events:e=[],profile:t=null,revisionLinks:n=[],now:r=new Date,app:i={version:``,storage:`memory`,provider:null},capstone:a={started:!1,submissions:0,externalEvidence:0,verdict:null}}={}){if(!t||t.participant_id==null)throw Error(`A beta profile with participant_id is required to build a report`);let o=re({events:e,profile:t,now:r}),s={schemaVersion:1,participantId:t.participant_id,generatedAtDayOffset:o.generatedAtDayOffset,app:{version:i?.version??``,storage:i?.storage??`memory`,provider:i?.provider??null},activation:{activated:o.activation.activated,firstEventKind:o.activation.firstEventKind},window:{activeDayOffsets:o.window.activeDayOffsets},loops:{byKind:o.loops.byKind,revisions:I(n)},retention:{week1Active:o.retention.week1Active,week2Return:o.retention.week2Return,week2MeaningfulDays:o.retention.week2MeaningfulDays},capstone:{started:a?.started??!1,submissions:a?.submissions??0,externalEvidence:a?.externalEvidence??0,verdict:a?.verdict??null}};return F.parse(s)}var R=d(),z=`0.2.0-beta.0`,B=/^(bridge|byok):(anthropic|openai|openrouter|groq|lmstudio|ollama|custom|claude|opencode|cursor|gemini|antigravity)$/;function V(e=z){return typeof e==`string`?e:``}function H(e={}){let t=e?.provider,n=null;return t===`bridge`?n=`bridge:${e?.bridge?.agent||`claude`}`:t===`openai`?n=`byok:${e?.openai?.preset||``}`:t&&(n=`byok:${t}`),n&&B.test(n)?n:null}async function U(e=[]){let t={started:!1,submissions:0,externalEvidence:0,verdict:null},n=-1;for(let r of e||[]){let e=await a(r.id);if(e){t.started=!0;for(let r of await f(e.id)){t.submissions+=1,r?.testResults?.source===`external`&&(t.externalEvidence+=1);let e=Number(r?.attempt??0);if(e>=n){n=e;let i=r?.verdict;t.verdict=i===`course_complete`||i===`needs_work`?i:null}}}}return t}function W(e){let t=F.safeParse(e);if(!t.success){let e=t.error.issues.map(e=>`${e.path.join(`.`)||`(root)`}: ${e.message}`).join(`; `);throw Object.assign(Error(`Beta report failed schema validation — ${e}`),{code:`beta_report_invalid`})}let n=t.data;return{report:n,json:JSON.stringify(n,null,2),filename:`professor-beta-report-${String(n.participantId).slice(0,8)}-d${n.generatedAtDayOffset}.json`}}async function G({now:e=new Date,settings:t=n()}={}){let[r,i,a,s,c]=await Promise.all([l(),g(),h(),o(),p()]),u=await U(c);return W(L({events:r,profile:i,revisionLinks:a,now:e,app:{version:V(),storage:s?.kind??`memory`,provider:H(t)},capstone:u}))}function K(e){return E(e.filename,e.json,`application/json`),$(`exported`,e?.report?.generatedAtDayOffset),e}function q(e){return()=>K(e)}function J({payload:e,onDownload:t,busy:n=!1,error:r=null}){let i=s();if(r){let e=r?.code===`beta_report_invalid`;return(0,R.jsxs)(`p`,{role:`status`,className:`text-sm text-red-600 dark:text-red-400`,children:[i(`betaReport.error`),` `,e?i(`betaReport.invalid`):``]})}if(!e)return null;let{report:a,json:o,filename:c}=e,l=e=>i(e?`betaReport.values.yes`:`betaReport.values.no`),d=a.window.activeDayOffsets||[],f=a.loops.revisions,p=(f?.explicit??0)+(f?.inferred??0),m=a.capstone,h=m.started?i(`betaReport.values.started`):i(`betaReport.values.notStarted`),g=m.verdict===`course_complete`?i(`betaReport.values.courseComplete`):m.verdict===`needs_work`?i(`betaReport.values.needsWork`):i(`betaReport.values.none`);return(0,R.jsxs)(`div`,{className:`space-y-3`,children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`p`,{className:`text-sm font-medium`,children:i(`betaReport.summaryTitle`)}),(0,R.jsxs)(`dl`,{className:`mt-2 grid gap-x-4 gap-y-1 text-sm sm:grid-cols-2`,children:[(0,R.jsx)(`dt`,{className:`text-neutral-500`,children:i(`betaReport.summary.activation`)}),(0,R.jsx)(`dd`,{children:a.activation.activated?i(`betaReport.values.activated`):i(`betaReport.values.notActivated`)}),(0,R.jsx)(`dt`,{className:`text-neutral-500`,children:i(`betaReport.summary.window`)}),(0,R.jsx)(`dd`,{children:d.length?d.join(`, `):i(`betaReport.values.none`)}),(0,R.jsx)(`dt`,{className:`text-neutral-500`,children:i(`betaReport.summary.loops`)}),(0,R.jsx)(`dd`,{children:(0,R.jsx)(`ul`,{className:`space-y-0.5`,children:Object.entries(a.loops.byKind||{}).map(([e,t])=>(0,R.jsxs)(`li`,{children:[i(`betaReport.kinds.${e}`),`: `,t]},e))})}),(0,R.jsx)(`dt`,{className:`text-neutral-500`,children:i(`betaReport.summary.revisions`)}),(0,R.jsx)(`dd`,{children:p}),(0,R.jsx)(`dt`,{className:`text-neutral-500`,children:i(`betaReport.summary.retention`)}),(0,R.jsxs)(`dd`,{children:[i(`betaReport.values.week1`),` `,l(a.retention.week1Active),` ·`,` `,i(`betaReport.values.week2`),` `,l(a.retention.week2Return)]}),(0,R.jsx)(`dt`,{className:`text-neutral-500`,children:i(`betaReport.summary.capstone`)}),(0,R.jsxs)(`dd`,{children:[h,` · `,m.submissions,` · `,m.externalEvidence,` ·`,` `,g]}),(0,R.jsx)(`dt`,{className:`text-neutral-500`,children:i(`betaReport.summary.version`)}),(0,R.jsx)(`dd`,{children:a.app.version||`—`}),(0,R.jsx)(`dt`,{className:`text-neutral-500`,children:i(`betaReport.summary.storage`)}),(0,R.jsx)(`dd`,{children:i(`betaReport.storage.${a.app.storage}`)})]})]}),(0,R.jsx)(`p`,{className:`text-xs text-neutral-500`,children:i(`betaReport.everythingInFile`)}),(0,R.jsx)(`pre`,{className:`max-h-80 overflow-auto rounded-lg bg-neutral-100 p-3 text-xs dark:bg-neutral-800`,children:(0,R.jsx)(`code`,{children:o})}),(0,R.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,R.jsx)(u,{onClick:t,disabled:n,children:i(`betaReport.download`)}),(0,R.jsx)(`span`,{className:`text-xs text-neutral-500`,children:c})]})]})}function Y({checkpoint:e,onDismiss:t}){let n=s();return(0,R.jsx)(`div`,{className:`rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200`,children:(0,R.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,R.jsxs)(`span`,{children:[n(e===7?`betaReport.nudge.day7`:`betaReport.nudge.day14`),` `,(0,R.jsx)(c,{to:`/settings?report=1`,className:`underline`,children:n(`betaReport.nudge.action`)}),`.`]}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`shrink-0 text-xs opacity-70 hover:opacity-100`,children:n(`betaReport.nudge.dismiss`)})]})})}function ie(){let e=s(),[t,n]=(0,D.useState)(null),[r,i]=(0,D.useState)(!1),[a,o]=(0,D.useState)(null);return(0,R.jsxs)(m,{id:`beta-report`,className:`space-y-4`,children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`p`,{className:`font-medium`,children:e(`betaReport.title`)}),(0,R.jsx)(`p`,{className:`mt-1 text-sm text-neutral-600 dark:text-neutral-300`,children:e(`betaReport.subtitle`)})]}),!t&&(0,R.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,R.jsx)(u,{onClick:async()=>{i(!0),o(null);try{n(await G())}catch(e){n(null),o(e)}finally{i(!1)}},disabled:r,children:e(`betaReport.open`)}),r&&(0,R.jsx)(`span`,{className:`text-xs text-neutral-500`,children:e(`betaReport.building`)})]}),t&&(0,R.jsx)(J,{payload:t,onDownload:q(t),busy:r,error:a}),!t&&a&&(0,R.jsx)(J,{error:a,busy:r})]})}var X=Object.freeze([7,14]),ae=Object.freeze([`dismissed`,`exported`]),oe=`professor-studio:beta-report`;function Z(e,t){return`${oe}-${e}:${t}`}function Q(){try{return typeof localStorage>`u`?void 0:localStorage}catch{return}}function se(e=Q()){let t={dismissed:[],exported:[]};for(let n of ae)for(let r of X){let i;try{i=e?.getItem?.(Z(n,r))}catch{i=null}i===`1`&&t[n].push(r)}return t}function $(e,t,n=Q()){if(!n||typeof n.setItem!=`function`)return!1;try{return n.setItem(Z(e,t),`1`),!0}catch{return!1}}function ce(e,t=new Date){let n=e?.activated_day;return typeof n!=`string`||!n?null:j(r(t),n)}function le({offset:e,dismissed:t=[],exported:n=[]}={}){return!X.includes(e)||t.includes(e)||n.includes(e)?null:e}export{se as a,le as i,ie as n,$ as o,ce as r,Y as t};
@@ -1,4 +1,4 @@
1
- import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{t}from"./react-B8SKf8RM.js";import{f as n}from"./settings-DhwuyNPU.js";import{B as r,Ct as i,J as a,Lt as o,Nt as s,Rt as c,Y as l,_ as u,_t as d,at as f,d as p,f as m,g as h,gt as g,h as _,i as v,l as y,nt as b,p as x,t as S,y as C}from"./index-DioXTZVc.js";import{n as w,t as T}from"./TutorPanel-DXQ6Z3BY.js";import{_ as E,a as D,b as O,c as ee,d as te,f as k,g as ne,h as re,i as ie,l as ae,m as oe,o as se,p as ce,r as le,s as ue,t as de,u as fe,v as pe,x as me,y as he}from"./capstone-Amn6Hztq.js";import{t as ge}from"./useStream-rdsR6A7P.js";import{t as _e}from"./course-export-DpaOTT3a.js";import{t as ve}from"./Progress-CRc_xEWC.js";var A=e(t(),1),j=h();function ye({artifact:e,className:t=``}){let n=o();if(!e)return null;let r=String(e.title||``).trim(),i=String(e.deliverable||``).trim(),a=Array.isArray(e.definitionOfDone)?e.definitionOfDone.filter(Boolean):[];return!r&&!i&&!a.length?null:(0,j.jsxs)(x,{className:`border-indigo-200 bg-indigo-50/60 dark:border-indigo-500/30 dark:bg-indigo-500/5 ${t}`,children:[(0,j.jsx)(`p`,{className:`text-xs font-semibold uppercase tracking-wide text-indigo-600 dark:text-indigo-300`,children:n(`capstone.yourArtifact`)}),r&&(0,j.jsx)(`p`,{className:`mt-1 font-medium`,children:r}),i&&(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-700 dark:text-neutral-200`,children:i}),a.length>0&&(0,j.jsxs)(`div`,{className:`mt-3`,children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:n(`capstone.definitionOfDone`)}),(0,j.jsx)(`ul`,{className:`mt-1 list-disc space-y-0.5 pl-5 text-sm text-neutral-600 dark:text-neutral-300`,children:a.map((e,t)=>(0,j.jsx)(`li`,{children:e},t))})]})]})}function be({rubric:e,title:t,className:n=``}){let r=o(),i=Array.isArray(e)?e.filter(e=>e&&e.name):[];return i.length?(0,j.jsxs)(`div`,{className:n,children:[(0,j.jsx)(`p`,{className:`text-sm font-semibold`,children:t||r(`capstone.rubric`)}),(0,j.jsx)(`ul`,{className:`mt-2 space-y-2`,children:i.map((e,t)=>(0,j.jsxs)(`li`,{className:`rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:e.name}),e.solid&&(0,j.jsx)(`p`,{className:`mt-0.5 text-sm text-neutral-500`,children:e.solid})]},t))})]}):null}function M({path:e=``,code:t=``}={}){let n=typeof e==`string`?e.trim():``,r=typeof t==`string`?t:String(t??``);return!n||!r.trim()?null:{[n]:r}}function xe({programming:e=!1,workspaceFiles:t=[],onSubmit:n,busy:r=!1,error:i=null,onDismissError:a,external:s=!1,spec:c={path:``,code:``},onSpecChange:l=null,onDraftChange:u=null,evidenceReady:d=!1,evidenceLabel:f=``}){let h=o(),[g,_]=(0,A.useState)(``),[b,S]=(0,A.useState)(``),[C,w]=(0,A.useState)(!1),T=Array.isArray(t)&&t.length>0,E=s?M(c):null,D=s?!r&&d&&(!!E||g.trim().length>0):!r&&(g.trim().length>0||b.trim().length>0||C&&T),O=e=>{_(e),u?.(e)};return(0,j.jsxs)(x,{className:`space-y-3`,children:[(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`h2`,{className:`font-semibold`,children:h(`capstone.submit`)}),(0,j.jsx)(`p`,{className:`mt-1 text-xs text-neutral-500`,children:h(`capstone.submitIntro`)})]}),s&&(0,j.jsxs)(`div`,{className:`space-y-3 rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:h(`externalEvidence.specCodeTitle`)}),(0,j.jsx)(`p`,{className:`mt-1 text-xs text-neutral-500`,children:h(`externalEvidence.specCodeHint`)})]}),(0,j.jsx)(y,{label:h(`externalEvidence.specPathLabel`),name:`capstone-spec-path`,value:c.path,placeholder:`tests/checkout.spec.js`,onChange:e=>l?.({...c,path:e.target.value})}),(0,j.jsx)(p,{label:h(`externalEvidence.specCodeLabel`),name:`capstone-spec-code`,rows:10,value:c.code,onChange:e=>l?.({...c,code:e.target.value})})]}),(0,j.jsx)(p,{label:h(`capstone.submissionLabel`),name:`capstone-submission`,rows:6,value:g,onChange:e=>O(e.target.value),placeholder:h(`capstone.submissionPlaceholder`)}),(0,j.jsx)(y,{label:h(`capstone.repoLabel`),name:`capstone-repo`,value:b,onChange:e=>S(e.target.value),placeholder:`https://github.com/you/project`}),!s&&e&&T&&(0,j.jsxs)(`label`,{className:`flex items-start gap-2 rounded-lg border border-neutral-200 p-3 text-sm dark:border-neutral-800`,children:[(0,j.jsx)(`input`,{type:`checkbox`,className:`mt-0.5`,checked:C,onChange:e=>w(e.target.checked)}),(0,j.jsxs)(`span`,{children:[h(`capstone.useFiles`),(0,j.jsx)(`span`,{className:`block text-xs text-neutral-500`,children:h(`capstone.useFilesHint`,{count:t.length,fileWord:t.length===1?``:`s`})})]})]}),s&&(d?(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:f}):(0,j.jsx)(`p`,{className:`text-xs text-amber-700 dark:text-amber-300`,children:h(`externalEvidence.submitRequiresEvidence`)})),i&&(0,j.jsx)(v,{error:i,onDismiss:a}),(0,j.jsx)(`div`,{className:`flex items-center justify-end`,children:(0,j.jsx)(m,{onClick:()=>{if(!D)return;let e=s?E:C&&T?Object.fromEntries(t.map(e=>[e.path,String(e.content??``)])):null;n({content_md:g.trim(),repo_url:b.trim()||null,files:e})},disabled:!D,children:h(r?`capstone.reviewing`:`capstone.submit`)})})]})}var Se=[`total`,`passed`,`failed`,`skipped`,`flaky`],Ce=10;function we(e,t){return{total:e(`externalEvidence.total`),passed:e(`externalEvidence.passed`),failed:e(`externalEvidence.failed`),skipped:e(`externalEvidence.skipped`),flaky:e(`externalEvidence.flaky`)}[t]||t}function Te(e,t){return{no_tests:e(`externalEvidence.warning.no_tests`),count_mismatch:e(`externalEvidence.warning.count_mismatch`),unknown_spec_files:e(`externalEvidence.warning.unknown_spec_files`),claimed_pass_with_failures:e(`externalEvidence.warning.claimed_pass_with_failures`),unrecognized_format:e(`externalEvidence.warning.unrecognized_format`),truncated:e(`externalEvidence.warning.truncated`)}[t]||null}function Ee(e,t){let n={confirmed:e(`externalEvidence.chromiumConfirmed`),assumed:e(`externalEvidence.chromiumAssumed`),none:e(`externalEvidence.chromiumNone`)};return n[t]||n.none}function De(e){let t=Math.max(0,Number(e)||0);return t>=1e3?`${(t/1e3).toFixed(1)} s`:`${t} ms`}var N={confirmed:`accent`,assumed:`warning`,none:`neutral`};function P({evidence:e,compact:t=!1}){let n=o();if(!e||typeof e!=`object`)return null;let r=e.stats&&typeof e.stats==`object`?e.stats:{},i=Array.isArray(e.specs)?e.specs:[],a=Array.isArray(e.warnings)?e.warnings:[],s=Number(r.failed)||0,c=Array.isArray(r.projects)?r.projects.filter(Boolean):[],l=r.chromium||`none`;return(0,j.jsxs)(`div`,{className:`space-y-3 rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,j.jsx)(_,{tone:`warning`,children:n(`externalEvidence.selfReported`)}),!t&&(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:n(`externalEvidence.selfReportedHint`)})]}),(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:n(`externalEvidence.factsTitle`)}),(0,j.jsx)(`dl`,{className:`mt-1 grid grid-cols-2 gap-x-4 gap-y-1 text-sm sm:grid-cols-5`,children:Se.map(e=>(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`dt`,{className:`text-xs text-neutral-500`,children:we(n,e)}),(0,j.jsx)(`dd`,{className:e===`failed`&&s>0?`font-semibold text-amber-700 dark:text-amber-300`:`font-medium`,children:Number(r[e])||0})]},e))})]}),(0,j.jsxs)(`div`,{className:`space-y-1 text-sm text-neutral-600 dark:text-neutral-300`,children:[(0,j.jsx)(`p`,{children:n(`externalEvidence.durationLabel`,{ms:De(r.durationMs)})}),(0,j.jsx)(`p`,{children:r.playwrightVersion?n(`externalEvidence.versionLabel`,{version:r.playwrightVersion}):n(`externalEvidence.versionUnknown`)}),(0,j.jsxs)(`p`,{children:[n(`externalEvidence.projectsLabel`),`:`,` `,c.length?c.join(` · `):n(`externalEvidence.noProjects`)]}),(0,j.jsxs)(`p`,{className:`flex flex-wrap items-center gap-2`,children:[(0,j.jsxs)(`span`,{children:[n(`externalEvidence.chromiumLabel`),`:`]}),(0,j.jsx)(_,{tone:N[l]||`neutral`,children:Ee(n,l)})]})]}),!t&&(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:n(`externalEvidence.specsTitle`)}),i.length===0?(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-500`,children:n(`externalEvidence.noSpecs`)}):(0,j.jsx)(`ul`,{className:`mt-1 space-y-2 text-sm`,children:i.map((e,t)=>{let r=Array.isArray(e?.tests)?e.tests:[];return(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`p`,{className:`font-mono text-xs`,children:String(e?.file??``)}),(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:n(`externalEvidence.testCount`,{count:r.length})}),t<Ce&&r.length>0&&(0,j.jsx)(`ul`,{className:`mt-1 list-disc space-y-0.5 pl-5 text-neutral-600 dark:text-neutral-300`,children:r.map((e,t)=>(0,j.jsx)(`li`,{children:String(e?.title??``)},t))})]},`${String(e?.file??``)}-${t}`)})}),(0,j.jsx)(`p`,{className:`mt-2 text-xs text-neutral-500`,children:n(`externalEvidence.formatValue`,{format:String(e.format||`unknown`)})})]}),(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:n(`externalEvidence.warningsTitle`)}),a.length===0?(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-500`,children:n(`externalEvidence.warningNone`)}):(0,j.jsx)(`ul`,{className:`mt-1 list-disc space-y-1 pl-5 text-sm`,children:a.map((e,t)=>(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`span`,{className:`font-medium`,children:Te(n,e?.code)||String(e?.code??``)}),e?.detail?(0,j.jsx)(`span`,{className:`block text-xs text-neutral-500`,children:String(e.detail)}):null]},`${String(e?.code??``)}-${t}`))})]})]})}function F(e,t){let n=e?.key;if(n!=null&&String(n).trim())return String(n).trim();let r=e?.label||e?.name;return r!=null&&String(r).trim()?String(r).trim():`#${t}`}function I(e){return!e||typeof e!=`object`?null:e.status??null}function L(e=null,t=null){let n=k(e),r=k(t),i=Array.isArray(n?.criteria)?n.criteria:[],a=Array.isArray(r?.criteria)?r.criteria:[],o=i.length>0,s=a.length>0,c=s?a:i,l=new Map;return i.forEach((e,t)=>{let n=F(e,t);l.has(n)||l.set(n,e)}),c.map((e,t)=>{let n=F(e,t),r=I(l.get(n)||null),i=s?I(e):null;return{key:n,label:String(e?.label||e?.name||n),from:r,to:i,changed:o&&s&&r!==i}})}function Oe(e,t){return{met:e(`externalEvidence.status.met`),partial:e(`externalEvidence.status.partial`),not_met:e(`externalEvidence.status.not_met`)}[t]||String(t??``)}function R({previous:e=null,current:t=null}){let n=o(),r=L(e,t);if(!r.length)return null;let i=r.filter(e=>e.changed);return(0,j.jsxs)(`div`,{className:`mt-2 space-y-1`,children:[(0,j.jsx)(`p`,{className:`text-xs font-medium text-neutral-500`,children:n(`externalEvidence.historyTransitions`)}),i.length===0?(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:n(`externalEvidence.historyNoChange`)}):(0,j.jsx)(`ul`,{className:`space-y-1 text-xs text-neutral-600 dark:text-neutral-300`,children:i.map(e=>(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`span`,{className:`font-medium`,children:e.label}),`: `,e.from?Oe(n,e.from):n(`externalEvidence.historyFirstAttempt`),` → `,Oe(n,e.to)]},e.key))})]})}function z(e){if(!e)return``;try{return new Date(e).toLocaleString(void 0,{year:`numeric`,month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}catch{return String(e).slice(0,16)}}function ke(e,t){return t===`course_complete`?{tone:`success`,text:e(`capstone.verdictComplete`)}:t===`needs_work`?{tone:`warning`,text:e(`capstone.verdictNeedsWork`)}:{tone:`neutral`,text:e(`capstone.noVerdict`)}}function B({submission:e,previous:t=null}){let n=o(),r=ke(n,e.verdict),i=e.testResults?.source===`external`;return(0,j.jsxs)(`li`,{className:`rounded-lg border border-neutral-200 p-3 text-sm dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,j.jsxs)(`div`,{className:`min-w-0`,children:[(0,j.jsx)(`p`,{className:`font-medium`,children:n(`capstone.attemptN`,{n:e.attempt})}),(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:z(e.created_at)})]}),(0,j.jsx)(_,{tone:r.tone,children:r.text})]}),i&&(0,j.jsxs)(`div`,{className:`mt-3 space-y-2`,children:[(0,j.jsx)(`p`,{className:`text-xs font-medium text-neutral-500`,children:n(`externalEvidence.historyEvidence`)}),(0,j.jsx)(P,{evidence:e.testResults,compact:!0})]}),(0,j.jsx)(R,{previous:t?.review??null,current:e.review})]})}function Ae({submissions:e=[]}){let t=o();if(!e.length)return null;let n=[...e].reverse(),r=n.some(e=>e.testResults?.source===`external`);return(0,j.jsxs)(x,{className:`space-y-3`,children:[(0,j.jsxs)(`h2`,{className:`font-semibold`,children:[t(r?`externalEvidence.historyTitle`:`capstone.attempts`),` · `,e.length]}),(0,j.jsx)(`ul`,{className:`space-y-2`,children:n.map((e,t)=>(0,j.jsx)(B,{submission:e,previous:n[t+1]||null},e.id))})]})}var je={met:`success`,partial:`warning`,not_met:`neutral`};function Me({testResults:e}){let t=o();if(!e||!Array.isArray(e.checks)||!e.checks.length)return null;let n=oe(e.checks);return(0,j.jsxs)(`div`,{className:`rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:t(`capstone.automatedChecks`)}),(0,j.jsx)(_,{tone:n.failed?`warning`:`success`,children:t(`capstone.passedOf`,{passed:n.passed,total:n.total})})]}),(0,j.jsx)(`ul`,{className:`mt-2 space-y-1 text-sm`,children:e.checks.map((e,t)=>(0,j.jsxs)(`li`,{className:`flex items-start gap-2`,children:[(0,j.jsx)(`span`,{"aria-hidden":`true`,children:e.passed?`✅`:`❌`}),(0,j.jsxs)(`span`,{className:e.passed?`text-neutral-600 dark:text-neutral-300`:`text-neutral-800 dark:text-neutral-100`,children:[e.name,e.message&&!e.passed?(0,j.jsxs)(`span`,{className:`text-neutral-500`,children:[` — `,e.message]}):null]})]},t))})]})}function Ne({review:e,testResults:t=null,verdict:n=null}){let r=o();if(!e)return null;let i=k(e),a=(n??i?.verdict??null)===`course_complete`,s=Array.isArray(i?.criteria)?i.criteria:[],c=t?.source===`external`,l={R1:()=>r(`playwrightTemplate.rubric.r1`),R2:()=>r(`playwrightTemplate.rubric.r2`),R3:()=>r(`playwrightTemplate.rubric.r3`),R4:()=>r(`playwrightTemplate.rubric.r4`),R5:()=>r(`playwrightTemplate.rubric.r5`),R6:()=>r(`playwrightTemplate.rubric.r6`),R7:()=>r(`playwrightTemplate.rubric.r7`)},u={met:()=>r(`externalEvidence.status.met`),partial:()=>r(`externalEvidence.status.partial`),not_met:()=>r(`externalEvidence.status.not_met`)},d=e=>{let t=l[e?.key],n=t?t():null,r=`playwrightTemplate.rubric.${String(e?.key??``).toLowerCase()}`;return n&&n!==r?n:e?.label||e?.name||``},f=e=>{let t=u[e];return t?t():String(e??``)};return(0,j.jsxs)(x,{className:`space-y-4`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,j.jsx)(`h2`,{className:`font-semibold`,children:r(`capstone.reviewTitle`)}),(0,j.jsx)(_,{tone:a?`success`:`warning`,children:a?`🏆 ${r(`capstone.verdictComplete`)}`:`🔄 ${r(`capstone.verdictNeedsWork`)}`})]}),c?(0,j.jsx)(P,{evidence:t}):(0,j.jsx)(Me,{testResults:t}),Array.isArray(i?.strengths)&&i.strengths.length>0&&(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:r(`capstone.strengths`)}),(0,j.jsx)(`ul`,{className:`mt-1 list-disc space-y-0.5 pl-5 text-sm text-neutral-600 dark:text-neutral-300`,children:i.strengths.map((e,t)=>(0,j.jsx)(`li`,{children:e},t))})]}),(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:r(`capstone.rubric`)}),(0,j.jsx)(`ul`,{className:`mt-2 space-y-2`,children:s.map((e,t)=>(0,j.jsxs)(`li`,{className:`rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:d(e)}),(0,j.jsx)(_,{tone:je[e?.status]||`neutral`,children:f(e?.status)})]}),e?.question?(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-600 dark:text-neutral-300`,children:e.question}):null,e?.feedback?(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-600 dark:text-neutral-300`,children:e.feedback}):null]},`${String(e?.key??e?.name??``)}-${t}`))})]}),i?.nextAction&&(0,j.jsx)(`div`,{className:`rounded-lg bg-neutral-100 p-3 text-sm dark:bg-neutral-800`,children:r(`capstone.nextStep`,{text:i.nextAction})})]})}var V=2e5,H=2e3,Pe=32e3,U=Object.freeze([`no_tests`,`count_mismatch`,`unknown_spec_files`,`claimed_pass_with_failures`,`unrecognized_format`,`truncated`]),W=120,G=200,K=120,Fe=/\u001b\[[0-9;?]*[ -/]*[@-~]/g,q=/\u001b\][^\u0007]*(\u0007|\u001b\\)/g,Ie=`
1
+ import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{t}from"./react-B8SKf8RM.js";import{f as n}from"./settings-DhwuyNPU.js";import{B as r,Ct as i,J as a,Lt as o,Nt as s,Rt as c,Y as l,_ as u,_t as d,at as f,d as p,f as m,g as h,gt as g,h as _,i as v,l as y,nt as b,p as x,t as S,y as C}from"./index-CS8XPYbB.js";import{n as w,t as T}from"./TutorPanel-DQDWIU7f.js";import{_ as E,a as D,b as O,c as ee,d as te,f as k,g as ne,h as re,i as ie,l as ae,m as oe,o as se,p as ce,r as le,s as ue,t as de,u as fe,v as pe,x as me,y as he}from"./capstone-DhwBeNqk.js";import{t as ge}from"./useStream-rdsR6A7P.js";import{t as _e}from"./course-export-C8jSPuda.js";import{t as ve}from"./Progress-2rS19Fur.js";var A=e(t(),1),j=h();function ye({artifact:e,className:t=``}){let n=o();if(!e)return null;let r=String(e.title||``).trim(),i=String(e.deliverable||``).trim(),a=Array.isArray(e.definitionOfDone)?e.definitionOfDone.filter(Boolean):[];return!r&&!i&&!a.length?null:(0,j.jsxs)(x,{className:`border-indigo-200 bg-indigo-50/60 dark:border-indigo-500/30 dark:bg-indigo-500/5 ${t}`,children:[(0,j.jsx)(`p`,{className:`text-xs font-semibold uppercase tracking-wide text-indigo-600 dark:text-indigo-300`,children:n(`capstone.yourArtifact`)}),r&&(0,j.jsx)(`p`,{className:`mt-1 font-medium`,children:r}),i&&(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-700 dark:text-neutral-200`,children:i}),a.length>0&&(0,j.jsxs)(`div`,{className:`mt-3`,children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:n(`capstone.definitionOfDone`)}),(0,j.jsx)(`ul`,{className:`mt-1 list-disc space-y-0.5 pl-5 text-sm text-neutral-600 dark:text-neutral-300`,children:a.map((e,t)=>(0,j.jsx)(`li`,{children:e},t))})]})]})}function be({rubric:e,title:t,className:n=``}){let r=o(),i=Array.isArray(e)?e.filter(e=>e&&e.name):[];return i.length?(0,j.jsxs)(`div`,{className:n,children:[(0,j.jsx)(`p`,{className:`text-sm font-semibold`,children:t||r(`capstone.rubric`)}),(0,j.jsx)(`ul`,{className:`mt-2 space-y-2`,children:i.map((e,t)=>(0,j.jsxs)(`li`,{className:`rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:e.name}),e.solid&&(0,j.jsx)(`p`,{className:`mt-0.5 text-sm text-neutral-500`,children:e.solid})]},t))})]}):null}function M({path:e=``,code:t=``}={}){let n=typeof e==`string`?e.trim():``,r=typeof t==`string`?t:String(t??``);return!n||!r.trim()?null:{[n]:r}}function xe({programming:e=!1,workspaceFiles:t=[],onSubmit:n,busy:r=!1,error:i=null,onDismissError:a,external:s=!1,spec:c={path:``,code:``},onSpecChange:l=null,onDraftChange:u=null,evidenceReady:d=!1,evidenceLabel:f=``}){let h=o(),[g,_]=(0,A.useState)(``),[b,S]=(0,A.useState)(``),[C,w]=(0,A.useState)(!1),T=Array.isArray(t)&&t.length>0,E=s?M(c):null,D=s?!r&&d&&(!!E||g.trim().length>0):!r&&(g.trim().length>0||b.trim().length>0||C&&T),O=e=>{_(e),u?.(e)};return(0,j.jsxs)(x,{className:`space-y-3`,children:[(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`h2`,{className:`font-semibold`,children:h(`capstone.submit`)}),(0,j.jsx)(`p`,{className:`mt-1 text-xs text-neutral-500`,children:h(`capstone.submitIntro`)})]}),s&&(0,j.jsxs)(`div`,{className:`space-y-3 rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:h(`externalEvidence.specCodeTitle`)}),(0,j.jsx)(`p`,{className:`mt-1 text-xs text-neutral-500`,children:h(`externalEvidence.specCodeHint`)})]}),(0,j.jsx)(y,{label:h(`externalEvidence.specPathLabel`),name:`capstone-spec-path`,value:c.path,placeholder:`tests/checkout.spec.js`,onChange:e=>l?.({...c,path:e.target.value})}),(0,j.jsx)(p,{label:h(`externalEvidence.specCodeLabel`),name:`capstone-spec-code`,rows:10,value:c.code,onChange:e=>l?.({...c,code:e.target.value})})]}),(0,j.jsx)(p,{label:h(`capstone.submissionLabel`),name:`capstone-submission`,rows:6,value:g,onChange:e=>O(e.target.value),placeholder:h(`capstone.submissionPlaceholder`)}),(0,j.jsx)(y,{label:h(`capstone.repoLabel`),name:`capstone-repo`,value:b,onChange:e=>S(e.target.value),placeholder:`https://github.com/you/project`}),!s&&e&&T&&(0,j.jsxs)(`label`,{className:`flex items-start gap-2 rounded-lg border border-neutral-200 p-3 text-sm dark:border-neutral-800`,children:[(0,j.jsx)(`input`,{type:`checkbox`,className:`mt-0.5`,checked:C,onChange:e=>w(e.target.checked)}),(0,j.jsxs)(`span`,{children:[h(`capstone.useFiles`),(0,j.jsx)(`span`,{className:`block text-xs text-neutral-500`,children:h(`capstone.useFilesHint`,{count:t.length,fileWord:t.length===1?``:`s`})})]})]}),s&&(d?(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:f}):(0,j.jsx)(`p`,{className:`text-xs text-amber-700 dark:text-amber-300`,children:h(`externalEvidence.submitRequiresEvidence`)})),i&&(0,j.jsx)(v,{error:i,onDismiss:a}),(0,j.jsx)(`div`,{className:`flex items-center justify-end`,children:(0,j.jsx)(m,{onClick:()=>{if(!D)return;let e=s?E:C&&T?Object.fromEntries(t.map(e=>[e.path,String(e.content??``)])):null;n({content_md:g.trim(),repo_url:b.trim()||null,files:e})},disabled:!D,children:h(r?`capstone.reviewing`:`capstone.submit`)})})]})}var Se=[`total`,`passed`,`failed`,`skipped`,`flaky`],Ce=10;function we(e,t){return{total:e(`externalEvidence.total`),passed:e(`externalEvidence.passed`),failed:e(`externalEvidence.failed`),skipped:e(`externalEvidence.skipped`),flaky:e(`externalEvidence.flaky`)}[t]||t}function Te(e,t){return{no_tests:e(`externalEvidence.warning.no_tests`),count_mismatch:e(`externalEvidence.warning.count_mismatch`),unknown_spec_files:e(`externalEvidence.warning.unknown_spec_files`),claimed_pass_with_failures:e(`externalEvidence.warning.claimed_pass_with_failures`),unrecognized_format:e(`externalEvidence.warning.unrecognized_format`),truncated:e(`externalEvidence.warning.truncated`)}[t]||null}function Ee(e,t){let n={confirmed:e(`externalEvidence.chromiumConfirmed`),assumed:e(`externalEvidence.chromiumAssumed`),none:e(`externalEvidence.chromiumNone`)};return n[t]||n.none}function De(e){let t=Math.max(0,Number(e)||0);return t>=1e3?`${(t/1e3).toFixed(1)} s`:`${t} ms`}var N={confirmed:`accent`,assumed:`warning`,none:`neutral`};function P({evidence:e,compact:t=!1}){let n=o();if(!e||typeof e!=`object`)return null;let r=e.stats&&typeof e.stats==`object`?e.stats:{},i=Array.isArray(e.specs)?e.specs:[],a=Array.isArray(e.warnings)?e.warnings:[],s=Number(r.failed)||0,c=Array.isArray(r.projects)?r.projects.filter(Boolean):[],l=r.chromium||`none`;return(0,j.jsxs)(`div`,{className:`space-y-3 rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,j.jsx)(_,{tone:`warning`,children:n(`externalEvidence.selfReported`)}),!t&&(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:n(`externalEvidence.selfReportedHint`)})]}),(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:n(`externalEvidence.factsTitle`)}),(0,j.jsx)(`dl`,{className:`mt-1 grid grid-cols-2 gap-x-4 gap-y-1 text-sm sm:grid-cols-5`,children:Se.map(e=>(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`dt`,{className:`text-xs text-neutral-500`,children:we(n,e)}),(0,j.jsx)(`dd`,{className:e===`failed`&&s>0?`font-semibold text-amber-700 dark:text-amber-300`:`font-medium`,children:Number(r[e])||0})]},e))})]}),(0,j.jsxs)(`div`,{className:`space-y-1 text-sm text-neutral-600 dark:text-neutral-300`,children:[(0,j.jsx)(`p`,{children:n(`externalEvidence.durationLabel`,{ms:De(r.durationMs)})}),(0,j.jsx)(`p`,{children:r.playwrightVersion?n(`externalEvidence.versionLabel`,{version:r.playwrightVersion}):n(`externalEvidence.versionUnknown`)}),(0,j.jsxs)(`p`,{children:[n(`externalEvidence.projectsLabel`),`:`,` `,c.length?c.join(` · `):n(`externalEvidence.noProjects`)]}),(0,j.jsxs)(`p`,{className:`flex flex-wrap items-center gap-2`,children:[(0,j.jsxs)(`span`,{children:[n(`externalEvidence.chromiumLabel`),`:`]}),(0,j.jsx)(_,{tone:N[l]||`neutral`,children:Ee(n,l)})]})]}),!t&&(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:n(`externalEvidence.specsTitle`)}),i.length===0?(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-500`,children:n(`externalEvidence.noSpecs`)}):(0,j.jsx)(`ul`,{className:`mt-1 space-y-2 text-sm`,children:i.map((e,t)=>{let r=Array.isArray(e?.tests)?e.tests:[];return(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`p`,{className:`font-mono text-xs`,children:String(e?.file??``)}),(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:n(`externalEvidence.testCount`,{count:r.length})}),t<Ce&&r.length>0&&(0,j.jsx)(`ul`,{className:`mt-1 list-disc space-y-0.5 pl-5 text-neutral-600 dark:text-neutral-300`,children:r.map((e,t)=>(0,j.jsx)(`li`,{children:String(e?.title??``)},t))})]},`${String(e?.file??``)}-${t}`)})}),(0,j.jsx)(`p`,{className:`mt-2 text-xs text-neutral-500`,children:n(`externalEvidence.formatValue`,{format:String(e.format||`unknown`)})})]}),(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:n(`externalEvidence.warningsTitle`)}),a.length===0?(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-500`,children:n(`externalEvidence.warningNone`)}):(0,j.jsx)(`ul`,{className:`mt-1 list-disc space-y-1 pl-5 text-sm`,children:a.map((e,t)=>(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`span`,{className:`font-medium`,children:Te(n,e?.code)||String(e?.code??``)}),e?.detail?(0,j.jsx)(`span`,{className:`block text-xs text-neutral-500`,children:String(e.detail)}):null]},`${String(e?.code??``)}-${t}`))})]})]})}function F(e,t){let n=e?.key;if(n!=null&&String(n).trim())return String(n).trim();let r=e?.label||e?.name;return r!=null&&String(r).trim()?String(r).trim():`#${t}`}function I(e){return!e||typeof e!=`object`?null:e.status??null}function L(e=null,t=null){let n=k(e),r=k(t),i=Array.isArray(n?.criteria)?n.criteria:[],a=Array.isArray(r?.criteria)?r.criteria:[],o=i.length>0,s=a.length>0,c=s?a:i,l=new Map;return i.forEach((e,t)=>{let n=F(e,t);l.has(n)||l.set(n,e)}),c.map((e,t)=>{let n=F(e,t),r=I(l.get(n)||null),i=s?I(e):null;return{key:n,label:String(e?.label||e?.name||n),from:r,to:i,changed:o&&s&&r!==i}})}function Oe(e,t){return{met:e(`externalEvidence.status.met`),partial:e(`externalEvidence.status.partial`),not_met:e(`externalEvidence.status.not_met`)}[t]||String(t??``)}function R({previous:e=null,current:t=null}){let n=o(),r=L(e,t);if(!r.length)return null;let i=r.filter(e=>e.changed);return(0,j.jsxs)(`div`,{className:`mt-2 space-y-1`,children:[(0,j.jsx)(`p`,{className:`text-xs font-medium text-neutral-500`,children:n(`externalEvidence.historyTransitions`)}),i.length===0?(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:n(`externalEvidence.historyNoChange`)}):(0,j.jsx)(`ul`,{className:`space-y-1 text-xs text-neutral-600 dark:text-neutral-300`,children:i.map(e=>(0,j.jsxs)(`li`,{children:[(0,j.jsx)(`span`,{className:`font-medium`,children:e.label}),`: `,e.from?Oe(n,e.from):n(`externalEvidence.historyFirstAttempt`),` → `,Oe(n,e.to)]},e.key))})]})}function z(e){if(!e)return``;try{return new Date(e).toLocaleString(void 0,{year:`numeric`,month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}catch{return String(e).slice(0,16)}}function ke(e,t){return t===`course_complete`?{tone:`success`,text:e(`capstone.verdictComplete`)}:t===`needs_work`?{tone:`warning`,text:e(`capstone.verdictNeedsWork`)}:{tone:`neutral`,text:e(`capstone.noVerdict`)}}function B({submission:e,previous:t=null}){let n=o(),r=ke(n,e.verdict),i=e.testResults?.source===`external`;return(0,j.jsxs)(`li`,{className:`rounded-lg border border-neutral-200 p-3 text-sm dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,j.jsxs)(`div`,{className:`min-w-0`,children:[(0,j.jsx)(`p`,{className:`font-medium`,children:n(`capstone.attemptN`,{n:e.attempt})}),(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:z(e.created_at)})]}),(0,j.jsx)(_,{tone:r.tone,children:r.text})]}),i&&(0,j.jsxs)(`div`,{className:`mt-3 space-y-2`,children:[(0,j.jsx)(`p`,{className:`text-xs font-medium text-neutral-500`,children:n(`externalEvidence.historyEvidence`)}),(0,j.jsx)(P,{evidence:e.testResults,compact:!0})]}),(0,j.jsx)(R,{previous:t?.review??null,current:e.review})]})}function Ae({submissions:e=[]}){let t=o();if(!e.length)return null;let n=[...e].reverse(),r=n.some(e=>e.testResults?.source===`external`);return(0,j.jsxs)(x,{className:`space-y-3`,children:[(0,j.jsxs)(`h2`,{className:`font-semibold`,children:[t(r?`externalEvidence.historyTitle`:`capstone.attempts`),` · `,e.length]}),(0,j.jsx)(`ul`,{className:`space-y-2`,children:n.map((e,t)=>(0,j.jsx)(B,{submission:e,previous:n[t+1]||null},e.id))})]})}var je={met:`success`,partial:`warning`,not_met:`neutral`};function Me({testResults:e}){let t=o();if(!e||!Array.isArray(e.checks)||!e.checks.length)return null;let n=oe(e.checks);return(0,j.jsxs)(`div`,{className:`rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:t(`capstone.automatedChecks`)}),(0,j.jsx)(_,{tone:n.failed?`warning`:`success`,children:t(`capstone.passedOf`,{passed:n.passed,total:n.total})})]}),(0,j.jsx)(`ul`,{className:`mt-2 space-y-1 text-sm`,children:e.checks.map((e,t)=>(0,j.jsxs)(`li`,{className:`flex items-start gap-2`,children:[(0,j.jsx)(`span`,{"aria-hidden":`true`,children:e.passed?`✅`:`❌`}),(0,j.jsxs)(`span`,{className:e.passed?`text-neutral-600 dark:text-neutral-300`:`text-neutral-800 dark:text-neutral-100`,children:[e.name,e.message&&!e.passed?(0,j.jsxs)(`span`,{className:`text-neutral-500`,children:[` — `,e.message]}):null]})]},t))})]})}function Ne({review:e,testResults:t=null,verdict:n=null}){let r=o();if(!e)return null;let i=k(e),a=(n??i?.verdict??null)===`course_complete`,s=Array.isArray(i?.criteria)?i.criteria:[],c=t?.source===`external`,l={R1:()=>r(`playwrightTemplate.rubric.r1`),R2:()=>r(`playwrightTemplate.rubric.r2`),R3:()=>r(`playwrightTemplate.rubric.r3`),R4:()=>r(`playwrightTemplate.rubric.r4`),R5:()=>r(`playwrightTemplate.rubric.r5`),R6:()=>r(`playwrightTemplate.rubric.r6`),R7:()=>r(`playwrightTemplate.rubric.r7`)},u={met:()=>r(`externalEvidence.status.met`),partial:()=>r(`externalEvidence.status.partial`),not_met:()=>r(`externalEvidence.status.not_met`)},d=e=>{let t=l[e?.key],n=t?t():null,r=`playwrightTemplate.rubric.${String(e?.key??``).toLowerCase()}`;return n&&n!==r?n:e?.label||e?.name||``},f=e=>{let t=u[e];return t?t():String(e??``)};return(0,j.jsxs)(x,{className:`space-y-4`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,j.jsx)(`h2`,{className:`font-semibold`,children:r(`capstone.reviewTitle`)}),(0,j.jsx)(_,{tone:a?`success`:`warning`,children:a?`🏆 ${r(`capstone.verdictComplete`)}`:`🔄 ${r(`capstone.verdictNeedsWork`)}`})]}),c?(0,j.jsx)(P,{evidence:t}):(0,j.jsx)(Me,{testResults:t}),Array.isArray(i?.strengths)&&i.strengths.length>0&&(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:r(`capstone.strengths`)}),(0,j.jsx)(`ul`,{className:`mt-1 list-disc space-y-0.5 pl-5 text-sm text-neutral-600 dark:text-neutral-300`,children:i.strengths.map((e,t)=>(0,j.jsx)(`li`,{children:e},t))})]}),(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:r(`capstone.rubric`)}),(0,j.jsx)(`ul`,{className:`mt-2 space-y-2`,children:s.map((e,t)=>(0,j.jsxs)(`li`,{className:`rounded-lg border border-neutral-200 p-3 dark:border-neutral-800`,children:[(0,j.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,j.jsx)(`p`,{className:`text-sm font-medium`,children:d(e)}),(0,j.jsx)(_,{tone:je[e?.status]||`neutral`,children:f(e?.status)})]}),e?.question?(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-600 dark:text-neutral-300`,children:e.question}):null,e?.feedback?(0,j.jsx)(`p`,{className:`mt-1 text-sm text-neutral-600 dark:text-neutral-300`,children:e.feedback}):null]},`${String(e?.key??e?.name??``)}-${t}`))})]}),i?.nextAction&&(0,j.jsx)(`div`,{className:`rounded-lg bg-neutral-100 p-3 text-sm dark:bg-neutral-800`,children:r(`capstone.nextStep`,{text:i.nextAction})})]})}var V=2e5,H=2e3,Pe=32e3,U=Object.freeze([`no_tests`,`count_mismatch`,`unknown_spec_files`,`claimed_pass_with_failures`,`unrecognized_format`,`truncated`]),W=120,G=200,K=120,Fe=/\u001b\[[0-9;?]*[ -/]*[@-~]/g,q=/\u001b\][^\u0007]*(\u0007|\u001b\\)/g,Ie=`
2
2
  {
3
3
  "config":`,J=/\{\s*"config"\s*:/,Y=/^\s*(\d+)\s+(passed|failed|flaky|skipped|did not run|interrupted)\b(?:\s*\(([^)]+)\))?\s*$/i,X=/^\s*Running\s+(\d+)\s+tests?\s+using\s+(\d+)\s+workers?\b/i,Le=/^\s*([✓✘x-]|ok)\s+(\d+)\s+(?:\[([^\]]+)\]\s*›\s*)?(.+?):(\d+):(\d+)\s*›\s*(.+?)(?:\s+\(retry #(\d+)\))?(?:\s+\(([\d.]+)(ms|s)\))?\s*$/u,Re=/^\[(\d+)\/(\d+)\]\s+(?:\(retries\)\s+)?(?:\[([^\]]+)\]\s*›\s*)?(.+?):(\d+):(\d+)\s*›\s*(.+?)(?:\s+\(retry #(\d+)\))?\s*$/u,ze=[/all (?:the )?tests? (?:are )?(?:pass|green)/i,/100\s*%\s*pass/i,/tất cả.*(?:đạt|pass)/i];function Z(e,t){let n=String(e??``);return n.length>t?n.slice(0,t):n}function Q(e){try{let t=JSON.parse(e);return t&&typeof t==`object`?t:null}catch{return null}}function Be(e){return String(e??``).replace(Fe,``).replace(q,``).replace(/\r\n?/g,`
4
4
  `)}function Ve(e){let t=Be(e).trim();return t?t.startsWith(`{`)&&Q(t)||J.test(t)?`json`:t.split(`
@@ -1,2 +1,2 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./Editor-CV0mNhlz.js","./rolldown-runtime-COiEfhsA.js","./react-B8SKf8RM.js","./index-DioXTZVc.js","./settings-DhwuyNPU.js","./errors-BZa_CNHL.js","./index-CVenTTOY.css"])))=>i.map(i=>d[i]);
2
- import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{t}from"./react-B8SKf8RM.js";import{f as n}from"./settings-DhwuyNPU.js";import{Lt as r,St as i,Tt as a,W as o,Z as s,a as c,f as l,g as u,h as d,ht as ee,i as te,mt as f,p,xt as ne}from"./index-DioXTZVc.js";import{C as re,S as ie,a as m,c as ae,d as h,f as oe,h as se,i as g,o as ce,r as le,s as ue,u as de,x as _}from"./TutorPanel-DXQ6Z3BY.js";import{A as fe,D as v,E as pe,M as me,T as he,j as y,k as ge,w as b}from"./capstone-Amn6Hztq.js";var x=e(t(),1),S=u();function _e({files:e,activePath:t,onSelect:n,onAdd:i,onRename:a,onDelete:o}){let s=r();return(0,S.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,S.jsxs)(`div`,{className:`flex flex-1 gap-1 overflow-x-auto pb-1`,role:`tablist`,"aria-label":s(`workspace.title`),children:[e.map(r=>{let i=r.path===t;return(0,S.jsxs)(`div`,{className:`group flex shrink-0 items-center gap-1 rounded-t-lg border-b-2 px-2.5 py-1.5 text-sm ${i?`border-indigo-500 bg-white font-medium text-indigo-700 dark:bg-neutral-900 dark:text-indigo-300`:`border-transparent text-neutral-600 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-800`}`,children:[(0,S.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i,onClick:()=>n(r.path),onDoubleClick:()=>a(r.path),title:`${r.path} — double-click to rename`,className:`whitespace-nowrap`,children:r.path}),e.length>1&&(0,S.jsx)(`button`,{type:`button`,"aria-label":s(`workspace.deleteFile`,{path:r.path}),onClick:()=>o(r.path),className:`rounded px-1 text-xs text-neutral-400 opacity-0 hover:text-red-600 group-hover:opacity-100`,children:`×`})]},r.path)}),(0,S.jsx)(`button`,{type:`button`,onClick:i,className:`shrink-0 rounded px-2 py-1 text-sm text-neutral-500 hover:bg-neutral-100 hover:text-neutral-800 dark:hover:bg-neutral-800 dark:hover:text-neutral-100`,"aria-label":s(`workspace.addFile`),children:s(`workspace.addFile`)})]})})}function C({runnerInfo:e=null,className:t=``}){let n=r();if(!e?.kind)return null;let i=e.kind===`local`;return(0,S.jsx)(d,{tone:i?`accent`:`neutral`,className:t,children:n(i?`runnerNotice.badge.local`:`runnerNotice.badge.browser`)})}function ve({runnerInfo:e=null,acknowledged:t=!1,onAcknowledge:n=null,className:i=``}){let a=r();return e?.kind?(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 ${i}`.trim(),children:[(0,S.jsx)(C,{runnerInfo:e}),e.kind===`local`?(0,S.jsxs)(`div`,{className:`rounded-lg bg-amber-50 px-3 py-2 text-xs text-amber-800 dark:bg-amber-500/10 dark:text-amber-200`,children:[(0,S.jsx)(`strong`,{className:`block font-medium`,children:a(`runnerNotice.notice.title`)}),(0,S.jsx)(`p`,{children:a(`runnerNotice.notice.body`)}),!t&&typeof n==`function`?(0,S.jsx)(l,{size:`sm`,variant:`secondary`,className:`mt-2`,onClick:n,children:a(`runnerNotice.notice.acknowledge`)}):null,t?(0,S.jsx)(`p`,{className:`mt-1`,children:a(`runnerNotice.notice.acknowledged`)}):null]}):null]}):null}function w({checks:e}){let t=r();if(!e?.length)return null;let n=e.filter(e=>e.passed).length;return(0,S.jsxs)(`div`,{className:`space-y-1`,children:[(0,S.jsxs)(`p`,{className:`text-sm font-medium`,children:[t(`workspace.checks`),` `,(0,S.jsx)(`span`,{className:n===e.length?`text-green-600`:`text-amber-600`,children:t(`workspace.passedOf`,{passed:n,total:e.length})})]}),(0,S.jsx)(`ul`,{className:`space-y-1`,children:e.map((e,t)=>(0,S.jsxs)(`li`,{className:`flex items-start gap-2 text-sm`,children:[(0,S.jsx)(`span`,{"aria-hidden":`true`,className:e.passed?`text-green-600`:`text-red-600`,children:e.passed?`✓`:`✗`}),(0,S.jsxs)(`span`,{className:e.passed?`text-neutral-700 dark:text-neutral-200`:`text-red-700 dark:text-red-300`,children:[e.name,!e.passed&&e.message?(0,S.jsx)(`span`,{className:`block text-xs opacity-80`,children:e.message}):null]})]},`${e.name}-${t}`))})]})}function T({html:e}){let t=r(),n=(0,x.useRef)(null),i=()=>{n.current?.contentWindow?.postMessage({type:`preview-html`,html:e},`*`)};return(0,x.useEffect)(()=>{i()},[e]),(0,S.jsx)(`iframe`,{ref:n,title:t(`workspace.preview`),sandbox:`allow-scripts`,src:`./preview.html`,onLoad:i,className:`h-64 w-full rounded-lg border border-neutral-200 bg-white dark:border-neutral-800`},e)}function ye({columns:e,rows:t}){return e?.length?(0,S.jsx)(`div`,{className:`overflow-x-auto`,children:(0,S.jsxs)(`table`,{className:`w-full border-collapse text-sm`,children:[(0,S.jsx)(`thead`,{children:(0,S.jsx)(`tr`,{children:e.map(e=>(0,S.jsx)(`th`,{className:`border border-neutral-200 bg-neutral-50 px-2 py-1 text-left dark:border-neutral-800 dark:bg-neutral-800`,children:e},e))})}),(0,S.jsx)(`tbody`,{children:t.map((t,n)=>(0,S.jsx)(`tr`,{children:e.map(e=>(0,S.jsx)(`td`,{className:`border border-neutral-200 px-2 py-1 dark:border-neutral-800`,children:t[e]===null||t[e]===void 0?`NULL`:String(t[e])},e))},n))})]})}):null}function be({output:e,runnerInfo:t=null,criteria:n=[],onRevise:i=null,reviseHint:a=null,criteriaTitle:o=null}){let s=r();if(!e)return(0,S.jsxs)(`div`,{className:`rounded-lg border border-dashed border-neutral-300 p-4 text-sm text-neutral-500 dark:border-neutral-700`,children:[s(`workspace.pressRun`),` `,(0,S.jsx)(`span`,{className:`font-medium`,children:s(`workspace.run`)}),` `,s(`workspace.pressRunMid`),` `,(0,S.jsx)(`span`,{className:`font-medium`,children:s(`workspace.checkButton`)}),` `,s(`workspace.pressRunMid2`),t?.kind===`local`&&!t.ready&&(0,S.jsx)(`span`,{className:`mt-1 block text-amber-600 dark:text-amber-400`,children:t.command?s(`workspace.needsCommand`,{command:t.command}):s(`workspace.needsServer`)})]});let c=(e.runner===`local`||e.runner===`browser`?e.runner:null)??(t?.kind===`local`||t?.kind===`browser`?t.kind:null);return(0,S.jsxs)(`div`,{className:`space-y-3 text-sm`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[c?(0,S.jsx)(C,{runnerInfo:{kind:c}}):null,typeof e.exitCode==`number`&&(0,S.jsx)(d,{tone:e.exitCode===0?`success`:`warning`,children:s(`workspace.exit`,{code:e.exitCode})}),typeof e.durationMs==`number`&&(0,S.jsxs)(`span`,{className:`text-xs text-neutral-500`,children:[e.durationMs,` ms`]}),e.timedOut&&(0,S.jsx)(d,{tone:`warning`,children:s(`workspace.timedOut`)}),e.outputTruncated&&(0,S.jsx)(d,{tone:`warning`,children:s(`workspace.outputTruncated`)}),e.aborted&&(0,S.jsx)(d,{tone:`neutral`,children:s(`workspace.stopped`)})]}),e.statusText&&(0,S.jsx)(`p`,{className:`text-xs text-neutral-500`,children:e.statusText}),(0,S.jsx)(w,{checks:e.checks}),Array.isArray(n)&&n.length>0?(0,S.jsx)(h,{criteria:n,title:o,showRevise:typeof i==`function`,onRevise:i,reviseHint:a}):null,e.stdout?(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`p`,{className:`mb-1 text-xs font-medium uppercase tracking-wide text-neutral-500`,children:s(`workspace.stdout`)}),(0,S.jsx)(`pre`,{className:`max-h-64 overflow-auto rounded-lg bg-neutral-50 p-3 font-mono text-xs dark:bg-neutral-950`,children:e.stdout})]}):null,e.stderr?(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`p`,{className:`mb-1 text-xs font-medium uppercase tracking-wide text-neutral-500`,children:s(`workspace.stderr`)}),(0,S.jsx)(`pre`,{className:`max-h-64 overflow-auto rounded-lg bg-red-50 p-3 font-mono text-xs text-red-800 dark:bg-red-500/10 dark:text-red-200`,children:e.stderr})]}):null,e.rows?.columns?.length?(0,S.jsx)(ye,{columns:e.rows.columns,rows:e.rows.rows||[]}):null,e.preview?.html?(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`p`,{className:`mb-1 text-xs font-medium uppercase tracking-wide text-neutral-500`,children:s(`workspace.preview`)}),(0,S.jsx)(T,{html:e.preview.html})]}):null,!e.stdout&&!e.stderr&&!e.checks?.length&&!e.rows?.columns?.length&&!e.preview?.html&&(0,S.jsx)(`p`,{className:`text-neutral-500`,children:s(`workspace.noOutput`)})]})}function E(e){let t=new Date(e);return Number.isNaN(t.getTime())?``:t.toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}function xe({runs:e,onRestore:t,onClose:n}){let i=r(),a=[...e||[]].reverse();return(0,S.jsxs)(`div`,{className:`space-y-3`,children:[(0,S.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,S.jsx)(`h3`,{className:`font-medium`,children:i(`workspace.runHistory`)}),(0,S.jsx)(l,{variant:`ghost`,size:`sm`,onClick:n,children:i(`common.close`)})]}),!a.length&&(0,S.jsx)(`p`,{className:`text-sm text-neutral-500`,children:i(`workspace.noRuns`)}),(0,S.jsx)(`ul`,{className:`space-y-2`,children:a.map(e=>{let n=e.checks?.length||0,r=e.checks?.filter(e=>e.passed).length||0;return(0,S.jsxs)(`li`,{className:`rounded-lg border border-neutral-200 p-3 text-sm dark:border-neutral-800`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsx)(d,{tone:e.runner===`local`?`accent`:`neutral`,children:e.runner===`local`?i(`workspace.local`):i(`workspace.browser`)}),typeof e.exitCode==`number`&&(0,S.jsx)(d,{tone:e.exitCode===0?`success`:`warning`,children:i(`workspace.exit`,{code:e.exitCode})}),n>0&&(0,S.jsx)(d,{tone:r===n?`success`:`warning`,children:i(`workspace.passedOf`,{passed:r,total:n})}),(0,S.jsx)(`span`,{className:`text-xs text-neutral-500`,children:E(e.createdAt)}),(0,S.jsxs)(`span`,{className:`ml-auto flex items-center gap-2`,children:[e.hash&&(0,S.jsx)(`code`,{className:`text-xs text-neutral-400`,children:e.hash}),e.snapshot&&(0,S.jsx)(l,{variant:`secondary`,size:`sm`,onClick:()=>t(e),children:i(`workspace.restore`)})]})]}),e.stdout?(0,S.jsx)(`pre`,{className:`mt-2 max-h-24 overflow-auto font-mono text-xs text-neutral-600 dark:text-neutral-300`,children:e.stdout.slice(0,400)}):null]},e.id)})})]})}function Se({skeleton:e}){let t=r(),[n,i]=(0,x.useState)(!1),a=e.info?e.info.charAt(0).toUpperCase()+e.info.slice(1):e.info;return(0,S.jsxs)(`div`,{className:`space-y-2 rounded-lg border border-amber-300 bg-amber-50 p-3 text-sm text-amber-900 dark:border-amber-700 dark:bg-amber-950/40 dark:text-amber-200`,children:[(0,S.jsx)(`p`,{children:t(`workspace.unsupportedNotice`,{info:a})}),(0,S.jsx)(`pre`,{className:`max-h-80 overflow-auto rounded bg-white/70 p-2 text-xs dark:bg-neutral-900/70`,children:(0,S.jsx)(`code`,{children:e.content})}),(0,S.jsx)(l,{size:`sm`,variant:`secondary`,onClick:async()=>{try{await navigator.clipboard.writeText(e.content),i(!0)}catch{i(!1)}},children:t(n?`workspace.unsupportedCopied`:`workspace.unsupportedCopy`)})]})}var D=`professor.runnerNotice.ack`;function O(){try{return typeof globalThis<`u`?globalThis.localStorage??null:null}catch{return null}}function k(e){try{return v(e)}catch{return null}}function A(e=O()){if(!e||typeof e.getItem!=`function`)return null;try{let t=e.getItem(D);if(!t)return null;let n=JSON.parse(t);return!n||typeof n!=`object`||typeof n.url!=`string`?null:n}catch{return null}}function Ce(e,t=O()){let n=k(e);if(!n)return!1;let r=A(t);return!r||r.url!==n}function we(e,t=O(),n=new Date){let r=k(e);if(!r||!t||typeof t.setItem!=`function`)return null;let i={url:r,acknowledgedAt:n.toISOString()};try{t.setItem(D,JSON.stringify(i))}catch{}return i}function Te({runnerKind:e=null,acknowledged:t=!1}={}){return e===`local`&&t!==!0}function Ee({checks:e=[],files:t={},entry:n=null,language:r=null}={}){let i={files:t,entry:n,language:r,hash:m(t)};return{checks:Array.isArray(e)?e:[],snapshot:i}}function De(e={}){let t=null;if(e.checks_json)try{t=JSON.parse(e.checks_json)}catch{t=null}let n=Array.isArray(t)?t:Array.isArray(t?.checks)?t.checks:[],r=!Array.isArray(t)&&t?.snapshot?t.snapshot:null;return{id:e.id,runner:e.runner||`browser`,language:e.language||null,stdout:e.stdout||``,stderr:e.stderr||``,exitCode:e.exit_code??null,durationMs:e.duration_ms??null,createdAt:e.created_at||``,checks:n,snapshot:r,hash:r?.hash||null}}var j=/^[a-zA-Z]:[\\/]/,M=/[\u0000-\u001f\u007f]/,N=/\\/;function Oe(e){if(typeof e!=`string`)return!1;let t=e.trim();if(!t||t.length>512||M.test(t)||t.startsWith(`/`)||t.startsWith(`~`)||j.test(t)||N.test(t)||t.endsWith(`/`))return!1;let n=t.split(`/`);for(let e of n)if(e===``||e===`.`||e===`..`)return!1;return!0}function ke(e){return String(e||``).normalize(`NFKD`).replace(/[\u0300-\u036f]/g,``).toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).slice(0,80)||`workspace`}var Ae=(0,x.lazy)(()=>a(()=>import(`./Editor-CV0mNhlz.js`),__vite__mapDeps([0,1,2,3,4,5,6]),import.meta.url)),je={stdout:``,stderr:``,checks:[],rows:null,preview:null,exitCode:null,durationMs:null,runner:null,statusText:``,timedOut:!1,aborted:!1,outputTruncated:!1};function Me(){let[e,t]=(0,x.useState)(()=>typeof window<`u`&&!!window.matchMedia?.(`(prefers-color-scheme: dark)`).matches);return(0,x.useEffect)(()=>{if(typeof window>`u`||!window.matchMedia)return;let e=window.matchMedia(`(prefers-color-scheme: dark)`),n=()=>t(e.matches);return e.addEventListener?.(`change`,n),()=>e.removeEventListener?.(`change`,n)},[]),e}function P(e){return Object.fromEntries(e.map(e=>[e.path,e.content]))}function Ne(e){return/\.[a-z0-9]+$/i.test(e)?e:`${e}.js`}function F({lesson:e,course:t}){let a=r(),[u]=n(),d=Me(),m=t?.id||null,h=ke(t?.title||m||`workspace`),[v,C]=(0,x.useState)([]),[w,T]=(0,x.useState)(null),[ye,E]=(0,x.useState)(!1),[D,O]=(0,x.useState)(null),[k,A]=(0,x.useState)(null),[j,M]=(0,x.useState)(null),[N,F]=(0,x.useState)([]),[Pe,I]=(0,x.useState)(!1),[L,R]=(0,x.useState)(null),[z,Fe]=(0,x.useState)(()=>!Ce(u)),[Ie,B]=(0,x.useState)([]),[V,Le]=(0,x.useState)(null),[H,U]=(0,x.useState)(null),W=(0,x.useRef)(null),G=(0,x.useRef)({...je}),K=(0,x.useRef)(null),q=(0,x.useRef)(v),J=(0,x.useRef)(new Set),Re=(0,x.useRef)(null),Y=(0,x.useRef)(new Map),ze=(0,x.useRef)(null),Be=(0,x.useRef)(e?.content_md||``);q.current=v;let Ve=(0,x.useRef)(z);Ve.current=z;let He=(0,x.useCallback)(()=>{typeof requestAnimationFrame>`u`?A({...G.current}):K.current||=requestAnimationFrame(()=>{K.current=null,A({...G.current})})},[]),X=(0,x.useCallback)(async()=>{try{let t=await f(e.id);F(t.map(De))}catch{F([])}},[e?.id]);(0,x.useEffect)(()=>{let n=!0;return E(!1),Y.current=new Map,J.current=new Set,(async()=>{let r=[],a=!1,c=[],l=null;try{let[n,i,o]=await Promise.all([ee(e.id),f(e.id).catch(()=>[]),s(e.id).catch(()=>null)]);for(let e of n)Y.current.set(e.path,e.id);Be.current=o?.content_md||e?.content_md||``,{files:r,persist:a,stalePaths:c,unsupportedSkeleton:l}=ae({lesson:e,course:t,version:o,rows:n,runCount:i.length})}catch{({files:r,unsupportedSkeleton:l}=ue(e,t))}if(a)for(let t of r)try{let n=await i({courseId:m,lessonId:e.id,path:t.path,language:t.language,content:t.content});Y.current.set(t.path,n.id)}catch{}for(let t of c)try{await o({lessonId:e.id,path:t}),Y.current.delete(t)}catch{}n&&(U(l),C(r),T(r[0]?.path||null),E(!0),g(e.id,{language:r[0]?.language||null,entry:r[0]?.path||null,files:P(r)}))})(),X(),()=>{n=!1,K.current&&typeof cancelAnimationFrame<`u`&&cancelAnimationFrame(K.current),le(e.id)}},[e?.id]);let Z=ge(w?y(w):null);(0,x.useEffect)(()=>{if(!Z||Z.backend!==`local`||L)return;let e=!0;return pe(u).then(t=>e&&R(t)).catch(()=>e&&R(null)),()=>{e=!1}},[w,Z?.id,L]);let Ue=(0,x.useCallback)(async()=>{let t=[...J.current];J.current.clear();for(let n of t){let t=q.current.find(e=>e.path===n);if(t)try{let r=await i({courseId:m,lessonId:e.id,path:n,language:t.language,content:t.content});Y.current.set(n,r.id)}catch{}}},[m,e?.id]),We=(0,x.useCallback)(e=>{J.current.add(e),clearTimeout(Re.current),Re.current=setTimeout(Ue,1e3)},[Ue]),Ge=(0,x.useCallback)((e,t,{persist:n=!0}={})=>{C(n=>n.map(n=>n.path===e?{...n,content:t}:n)),n&&We(e)},[We]);(0,x.useEffect)(()=>{if(!w)return;let t=q.current.find(e=>e.path===w);g(e.id,{language:t?.language||null,entry:w,files:P(q.current)})},[w,JSON.stringify(v)]);let Ke=(0,x.useCallback)(e=>{let t=G.current;e.stream===`stdout`?t.stdout+=e.text:e.stream===`stderr`?t.stderr+=e.text:e.stream===`status`&&(t.statusText=e.text),He()},[He]),qe=(0,x.useCallback)(async n=>{if(D||!q.current.length)return;let r=q.current,i=r.find(e=>e.path===w)||r[0],o=me(i?.language)||fe(t)||y(i?.path)||`javascript`,s=b(o,{toolchains:L}).kind;if(Te({runnerKind:s,acknowledged:Ve.current}))M(Object.assign(Error(a(`runnerNotice.notice.blocked`)),{hint:a(`runnerNotice.notice.blockedHint`)}));else{M(null),O(n),W.current=new AbortController,G.current={...je},A({...G.current}),B([]);try{let t=await he({language:o,files:P(r),entry:i?.path,courseSlug:h,settings:u,signal:W.current.signal,onOutput:Ke});if(G.current={...G.current,...t},A({...G.current}),!t.aborted){B(_(t.checks??[],e=>a(`revision.workspace.fallbackQuestion`,{label:e.label})));let n=Ee({checks:t.checks,files:P(r),entry:i?.path,language:o}),s=se(ze),c=await ne({lessonId:e.id,fileId:Y.current.get(i?.path)||null,runner:t.runner,language:o,stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode,checks:n,durationMs:t.durationMs,revisionOf:s});Le(c?.id??null),await X()}}catch(e){e?.code===`aborted`||e?.name===`AbortError`?(G.current.aborted=!0,A({...G.current})):M(e)}finally{O(null),W.current=null}}},[w,t,h,e?.id,Ke,X,D,u,a,L]),Je=(0,x.useCallback)(()=>{W.current?.abort()},[]),Ye=(0,x.useCallback)(()=>{we(u),Fe(!0)},[u]),Xe=(0,x.useCallback)(()=>{oe(ze,re(V)),M(null)},[V]),Ze=(0,x.useCallback)(async()=>{let t=window.prompt(a(`workspace.newFileName`));if(!t)return;let n=Ne(t.trim());if(!Oe(n)){M(Object.assign(Error(a(`workspace.invalidFileName`)),{hint:a(`workspace.invalidFileHint`)}));return}if(q.current.some(e=>e.path===n)){T(n);return}let r=y(n),o=[...q.current,{path:n,content:``,language:r}];C(o),T(n);try{let t=await i({courseId:m,lessonId:e.id,path:n,language:r,content:``});Y.current.set(n,t.id)}catch{}},[m,e?.id]),Qe=(0,x.useCallback)(async t=>{let n=window.prompt(a(`workspace.renameTo`),t);if(!n||n.trim()===t)return;let r=n.trim();if(!Oe(r)||q.current.some(e=>e.path===r)){M(Object.assign(Error(a(`workspace.invalidOrDuplicate`)),{hint:a(`workspace.invalidOrDuplicateHint`)}));return}let s=q.current.find(e=>e.path===t);if(!s)return;let c=y(r)||s.language;C(e=>e.map(e=>e.path===t?{...e,path:r,language:c}:e)),w===t&&T(r);try{await i({courseId:m,lessonId:e.id,path:r,language:c,content:s.content}),await o({lessonId:e.id,path:t})}catch{}},[w,m,e?.id]),$e=(0,x.useCallback)(async t=>{if(q.current.length<=1||!window.confirm(a(`workspace.deleteFileConfirm`,{path:t})))return;let n=q.current.filter(e=>e.path!==t);C(n),w===t&&T(n[0]?.path||null);try{await o({lessonId:e.id,path:t})}catch{}},[w,m,e?.id]),et=(0,x.useCallback)(async()=>{if(!window.confirm(a(`workspace.resetConfirm`)))return;let n=ce({lesson:{...e,content_md:Be.current||e?.content_md||``},course:t,storedPaths:[...Y.current.keys()]});for(let t of n.deletePaths){J.current.delete(t);try{await o({lessonId:e.id,path:t}),Y.current.delete(t)}catch{}}if(U(n.unsupportedSkeleton),C(n.files),T(n.files[0]?.path||null),n.persist)for(let t of n.files)try{let n=await i({courseId:m,lessonId:e.id,path:t.path,language:t.language,content:t.content});Y.current.set(t.path,n.id)}catch{}},[t,m,e]),tt=(0,x.useCallback)(async t=>{let n=t.snapshot?.files;if(!n)return;let r=Object.entries(n).map(([e,t])=>({path:e,content:String(t??``),language:y(e)}));C(r),T(r[0]?.path||null),I(!1);for(let t of r)try{let n=await i({courseId:m,lessonId:e.id,path:t.path,language:t.language,content:t.content});Y.current.set(t.path,n.id)}catch{}},[m,e?.id]),Q=v.find(e=>e.path===w)||v[0]||null,$=b(Q?.language,{toolchains:L}),nt=V&&(k?.checks?.length??0)>0&&!ie(k?.checks)?Xe:null,rt=(0,x.useMemo)(()=>N.map((e,t)=>({id:e.id,label:a(`revision.history.attempt`,{n:t+1}),criteria:_(e.checks??[],e=>a(`revision.workspace.fallbackQuestion`,{label:e.label}))})),[N,a]);return ye?(0,S.jsxs)(p,{className:`space-y-3`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,S.jsx)(`h2`,{className:`font-medium`,children:a(`workspace.title`)}),$.kind===`local`&&!$.ready&&(0,S.jsx)(`span`,{className:`text-xs text-amber-600 dark:text-amber-400`,children:$.command?a(`workspace.needsCommandShort`,{command:$.command}):a(`workspace.needsServerShort`)})]}),(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsx)(l,{size:`sm`,onClick:()=>qe(`run`),disabled:!!D||!v.length,children:a(D===`run`?`workspace.running`:`workspace.run`)}),(0,S.jsx)(l,{size:`sm`,variant:`secondary`,onClick:()=>qe(`check`),disabled:!!D||!v.length,children:a(D===`check`?`workspace.check`:`workspace.checkButton`)}),D&&(0,S.jsx)(l,{size:`sm`,variant:`ghost`,onClick:Je,children:a(`workspace.stop`)}),(0,S.jsxs)(l,{size:`sm`,variant:`ghost`,onClick:()=>I(e=>!e),children:[a(`workspace.history`),N.length?` (${N.length})`:``]}),(0,S.jsx)(l,{size:`sm`,variant:`ghost`,onClick:et,children:a(`workspace.reset`)})]})]}),(0,S.jsx)(ve,{runnerInfo:$,acknowledged:z,onAcknowledge:Ye}),H?(0,S.jsx)(Se,{skeleton:H}):(0,S.jsx)(_e,{files:v,activePath:Q?.path,onSelect:T,onAdd:Ze,onRename:Qe,onDelete:$e}),Q?(0,S.jsx)(x.Suspense,{fallback:(0,S.jsxs)(`div`,{className:`flex h-64 items-center justify-center text-sm text-neutral-500`,children:[(0,S.jsx)(c,{}),` `,a(`workspace.loadingEditor`)]}),children:(0,S.jsx)(Ae,{value:Q.content,language:Q.language,dark:d,onChange:e=>Ge(Q.path,e)})}):null,j?(0,S.jsx)(te,{error:j,onDismiss:()=>M(null)}):null,(0,S.jsx)(be,{output:k,runnerInfo:$,criteria:Ie,criteriaTitle:a(`revision.workspace.criteriaTitle`),reviseHint:a(`revision.workspace.reviseHint`),onRevise:nt}),rt.length>0?(0,S.jsx)(de,{attempts:rt,title:a(`revision.history.title`)}):null,Pe?(0,S.jsx)(`div`,{className:`border-t border-neutral-200 pt-3 dark:border-neutral-800`,children:(0,S.jsx)(xe,{runs:N,onRestore:tt,onClose:()=>I(!1)})}):null]}):(0,S.jsxs)(p,{className:`flex items-center gap-2 text-sm text-neutral-500`,children:[(0,S.jsx)(c,{}),` `,a(`workspace.loading`)]})}export{F as CodeWorkspace};
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./Editor-Cw9j3cnp.js","./rolldown-runtime-COiEfhsA.js","./react-B8SKf8RM.js","./index-CS8XPYbB.js","./settings-DhwuyNPU.js","./errors-BZa_CNHL.js","./index-CVenTTOY.css"])))=>i.map(i=>d[i]);
2
+ import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{t}from"./react-B8SKf8RM.js";import{f as n}from"./settings-DhwuyNPU.js";import{Lt as r,St as i,Tt as a,W as o,Z as s,a as c,f as l,g as u,h as d,ht as ee,i as te,mt as f,p,xt as ne}from"./index-CS8XPYbB.js";import{C as re,S as ie,a as m,c as ae,d as h,f as oe,h as se,i as g,o as ce,r as le,s as ue,u as de,x as _}from"./TutorPanel-DQDWIU7f.js";import{A as fe,D as v,E as pe,M as me,T as he,j as y,k as ge,w as b}from"./capstone-DhwBeNqk.js";var x=e(t(),1),S=u();function _e({files:e,activePath:t,onSelect:n,onAdd:i,onRename:a,onDelete:o}){let s=r();return(0,S.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,S.jsxs)(`div`,{className:`flex flex-1 gap-1 overflow-x-auto pb-1`,role:`tablist`,"aria-label":s(`workspace.title`),children:[e.map(r=>{let i=r.path===t;return(0,S.jsxs)(`div`,{className:`group flex shrink-0 items-center gap-1 rounded-t-lg border-b-2 px-2.5 py-1.5 text-sm ${i?`border-indigo-500 bg-white font-medium text-indigo-700 dark:bg-neutral-900 dark:text-indigo-300`:`border-transparent text-neutral-600 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-800`}`,children:[(0,S.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i,onClick:()=>n(r.path),onDoubleClick:()=>a(r.path),title:`${r.path} — double-click to rename`,className:`whitespace-nowrap`,children:r.path}),e.length>1&&(0,S.jsx)(`button`,{type:`button`,"aria-label":s(`workspace.deleteFile`,{path:r.path}),onClick:()=>o(r.path),className:`rounded px-1 text-xs text-neutral-400 opacity-0 hover:text-red-600 group-hover:opacity-100`,children:`×`})]},r.path)}),(0,S.jsx)(`button`,{type:`button`,onClick:i,className:`shrink-0 rounded px-2 py-1 text-sm text-neutral-500 hover:bg-neutral-100 hover:text-neutral-800 dark:hover:bg-neutral-800 dark:hover:text-neutral-100`,"aria-label":s(`workspace.addFile`),children:s(`workspace.addFile`)})]})})}function C({runnerInfo:e=null,className:t=``}){let n=r();if(!e?.kind)return null;let i=e.kind===`local`;return(0,S.jsx)(d,{tone:i?`accent`:`neutral`,className:t,children:n(i?`runnerNotice.badge.local`:`runnerNotice.badge.browser`)})}function ve({runnerInfo:e=null,acknowledged:t=!1,onAcknowledge:n=null,className:i=``}){let a=r();return e?.kind?(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 ${i}`.trim(),children:[(0,S.jsx)(C,{runnerInfo:e}),e.kind===`local`?(0,S.jsxs)(`div`,{className:`rounded-lg bg-amber-50 px-3 py-2 text-xs text-amber-800 dark:bg-amber-500/10 dark:text-amber-200`,children:[(0,S.jsx)(`strong`,{className:`block font-medium`,children:a(`runnerNotice.notice.title`)}),(0,S.jsx)(`p`,{children:a(`runnerNotice.notice.body`)}),!t&&typeof n==`function`?(0,S.jsx)(l,{size:`sm`,variant:`secondary`,className:`mt-2`,onClick:n,children:a(`runnerNotice.notice.acknowledge`)}):null,t?(0,S.jsx)(`p`,{className:`mt-1`,children:a(`runnerNotice.notice.acknowledged`)}):null]}):null]}):null}function w({checks:e}){let t=r();if(!e?.length)return null;let n=e.filter(e=>e.passed).length;return(0,S.jsxs)(`div`,{className:`space-y-1`,children:[(0,S.jsxs)(`p`,{className:`text-sm font-medium`,children:[t(`workspace.checks`),` `,(0,S.jsx)(`span`,{className:n===e.length?`text-green-600`:`text-amber-600`,children:t(`workspace.passedOf`,{passed:n,total:e.length})})]}),(0,S.jsx)(`ul`,{className:`space-y-1`,children:e.map((e,t)=>(0,S.jsxs)(`li`,{className:`flex items-start gap-2 text-sm`,children:[(0,S.jsx)(`span`,{"aria-hidden":`true`,className:e.passed?`text-green-600`:`text-red-600`,children:e.passed?`✓`:`✗`}),(0,S.jsxs)(`span`,{className:e.passed?`text-neutral-700 dark:text-neutral-200`:`text-red-700 dark:text-red-300`,children:[e.name,!e.passed&&e.message?(0,S.jsx)(`span`,{className:`block text-xs opacity-80`,children:e.message}):null]})]},`${e.name}-${t}`))})]})}function T({html:e}){let t=r(),n=(0,x.useRef)(null),i=()=>{n.current?.contentWindow?.postMessage({type:`preview-html`,html:e},`*`)};return(0,x.useEffect)(()=>{i()},[e]),(0,S.jsx)(`iframe`,{ref:n,title:t(`workspace.preview`),sandbox:`allow-scripts`,src:`./preview.html`,onLoad:i,className:`h-64 w-full rounded-lg border border-neutral-200 bg-white dark:border-neutral-800`},e)}function ye({columns:e,rows:t}){return e?.length?(0,S.jsx)(`div`,{className:`overflow-x-auto`,children:(0,S.jsxs)(`table`,{className:`w-full border-collapse text-sm`,children:[(0,S.jsx)(`thead`,{children:(0,S.jsx)(`tr`,{children:e.map(e=>(0,S.jsx)(`th`,{className:`border border-neutral-200 bg-neutral-50 px-2 py-1 text-left dark:border-neutral-800 dark:bg-neutral-800`,children:e},e))})}),(0,S.jsx)(`tbody`,{children:t.map((t,n)=>(0,S.jsx)(`tr`,{children:e.map(e=>(0,S.jsx)(`td`,{className:`border border-neutral-200 px-2 py-1 dark:border-neutral-800`,children:t[e]===null||t[e]===void 0?`NULL`:String(t[e])},e))},n))})]})}):null}function be({output:e,runnerInfo:t=null,criteria:n=[],onRevise:i=null,reviseHint:a=null,criteriaTitle:o=null}){let s=r();if(!e)return(0,S.jsxs)(`div`,{className:`rounded-lg border border-dashed border-neutral-300 p-4 text-sm text-neutral-500 dark:border-neutral-700`,children:[s(`workspace.pressRun`),` `,(0,S.jsx)(`span`,{className:`font-medium`,children:s(`workspace.run`)}),` `,s(`workspace.pressRunMid`),` `,(0,S.jsx)(`span`,{className:`font-medium`,children:s(`workspace.checkButton`)}),` `,s(`workspace.pressRunMid2`),t?.kind===`local`&&!t.ready&&(0,S.jsx)(`span`,{className:`mt-1 block text-amber-600 dark:text-amber-400`,children:t.command?s(`workspace.needsCommand`,{command:t.command}):s(`workspace.needsServer`)})]});let c=(e.runner===`local`||e.runner===`browser`?e.runner:null)??(t?.kind===`local`||t?.kind===`browser`?t.kind:null);return(0,S.jsxs)(`div`,{className:`space-y-3 text-sm`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[c?(0,S.jsx)(C,{runnerInfo:{kind:c}}):null,typeof e.exitCode==`number`&&(0,S.jsx)(d,{tone:e.exitCode===0?`success`:`warning`,children:s(`workspace.exit`,{code:e.exitCode})}),typeof e.durationMs==`number`&&(0,S.jsxs)(`span`,{className:`text-xs text-neutral-500`,children:[e.durationMs,` ms`]}),e.timedOut&&(0,S.jsx)(d,{tone:`warning`,children:s(`workspace.timedOut`)}),e.outputTruncated&&(0,S.jsx)(d,{tone:`warning`,children:s(`workspace.outputTruncated`)}),e.aborted&&(0,S.jsx)(d,{tone:`neutral`,children:s(`workspace.stopped`)})]}),e.statusText&&(0,S.jsx)(`p`,{className:`text-xs text-neutral-500`,children:e.statusText}),(0,S.jsx)(w,{checks:e.checks}),Array.isArray(n)&&n.length>0?(0,S.jsx)(h,{criteria:n,title:o,showRevise:typeof i==`function`,onRevise:i,reviseHint:a}):null,e.stdout?(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`p`,{className:`mb-1 text-xs font-medium uppercase tracking-wide text-neutral-500`,children:s(`workspace.stdout`)}),(0,S.jsx)(`pre`,{className:`max-h-64 overflow-auto rounded-lg bg-neutral-50 p-3 font-mono text-xs dark:bg-neutral-950`,children:e.stdout})]}):null,e.stderr?(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`p`,{className:`mb-1 text-xs font-medium uppercase tracking-wide text-neutral-500`,children:s(`workspace.stderr`)}),(0,S.jsx)(`pre`,{className:`max-h-64 overflow-auto rounded-lg bg-red-50 p-3 font-mono text-xs text-red-800 dark:bg-red-500/10 dark:text-red-200`,children:e.stderr})]}):null,e.rows?.columns?.length?(0,S.jsx)(ye,{columns:e.rows.columns,rows:e.rows.rows||[]}):null,e.preview?.html?(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`p`,{className:`mb-1 text-xs font-medium uppercase tracking-wide text-neutral-500`,children:s(`workspace.preview`)}),(0,S.jsx)(T,{html:e.preview.html})]}):null,!e.stdout&&!e.stderr&&!e.checks?.length&&!e.rows?.columns?.length&&!e.preview?.html&&(0,S.jsx)(`p`,{className:`text-neutral-500`,children:s(`workspace.noOutput`)})]})}function E(e){let t=new Date(e);return Number.isNaN(t.getTime())?``:t.toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}function xe({runs:e,onRestore:t,onClose:n}){let i=r(),a=[...e||[]].reverse();return(0,S.jsxs)(`div`,{className:`space-y-3`,children:[(0,S.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,S.jsx)(`h3`,{className:`font-medium`,children:i(`workspace.runHistory`)}),(0,S.jsx)(l,{variant:`ghost`,size:`sm`,onClick:n,children:i(`common.close`)})]}),!a.length&&(0,S.jsx)(`p`,{className:`text-sm text-neutral-500`,children:i(`workspace.noRuns`)}),(0,S.jsx)(`ul`,{className:`space-y-2`,children:a.map(e=>{let n=e.checks?.length||0,r=e.checks?.filter(e=>e.passed).length||0;return(0,S.jsxs)(`li`,{className:`rounded-lg border border-neutral-200 p-3 text-sm dark:border-neutral-800`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsx)(d,{tone:e.runner===`local`?`accent`:`neutral`,children:e.runner===`local`?i(`workspace.local`):i(`workspace.browser`)}),typeof e.exitCode==`number`&&(0,S.jsx)(d,{tone:e.exitCode===0?`success`:`warning`,children:i(`workspace.exit`,{code:e.exitCode})}),n>0&&(0,S.jsx)(d,{tone:r===n?`success`:`warning`,children:i(`workspace.passedOf`,{passed:r,total:n})}),(0,S.jsx)(`span`,{className:`text-xs text-neutral-500`,children:E(e.createdAt)}),(0,S.jsxs)(`span`,{className:`ml-auto flex items-center gap-2`,children:[e.hash&&(0,S.jsx)(`code`,{className:`text-xs text-neutral-400`,children:e.hash}),e.snapshot&&(0,S.jsx)(l,{variant:`secondary`,size:`sm`,onClick:()=>t(e),children:i(`workspace.restore`)})]})]}),e.stdout?(0,S.jsx)(`pre`,{className:`mt-2 max-h-24 overflow-auto font-mono text-xs text-neutral-600 dark:text-neutral-300`,children:e.stdout.slice(0,400)}):null]},e.id)})})]})}function Se({skeleton:e}){let t=r(),[n,i]=(0,x.useState)(!1),a=e.info?e.info.charAt(0).toUpperCase()+e.info.slice(1):e.info;return(0,S.jsxs)(`div`,{className:`space-y-2 rounded-lg border border-amber-300 bg-amber-50 p-3 text-sm text-amber-900 dark:border-amber-700 dark:bg-amber-950/40 dark:text-amber-200`,children:[(0,S.jsx)(`p`,{children:t(`workspace.unsupportedNotice`,{info:a})}),(0,S.jsx)(`pre`,{className:`max-h-80 overflow-auto rounded bg-white/70 p-2 text-xs dark:bg-neutral-900/70`,children:(0,S.jsx)(`code`,{children:e.content})}),(0,S.jsx)(l,{size:`sm`,variant:`secondary`,onClick:async()=>{try{await navigator.clipboard.writeText(e.content),i(!0)}catch{i(!1)}},children:t(n?`workspace.unsupportedCopied`:`workspace.unsupportedCopy`)})]})}var D=`professor.runnerNotice.ack`;function O(){try{return typeof globalThis<`u`?globalThis.localStorage??null:null}catch{return null}}function k(e){try{return v(e)}catch{return null}}function A(e=O()){if(!e||typeof e.getItem!=`function`)return null;try{let t=e.getItem(D);if(!t)return null;let n=JSON.parse(t);return!n||typeof n!=`object`||typeof n.url!=`string`?null:n}catch{return null}}function Ce(e,t=O()){let n=k(e);if(!n)return!1;let r=A(t);return!r||r.url!==n}function we(e,t=O(),n=new Date){let r=k(e);if(!r||!t||typeof t.setItem!=`function`)return null;let i={url:r,acknowledgedAt:n.toISOString()};try{t.setItem(D,JSON.stringify(i))}catch{}return i}function Te({runnerKind:e=null,acknowledged:t=!1}={}){return e===`local`&&t!==!0}function Ee({checks:e=[],files:t={},entry:n=null,language:r=null}={}){let i={files:t,entry:n,language:r,hash:m(t)};return{checks:Array.isArray(e)?e:[],snapshot:i}}function De(e={}){let t=null;if(e.checks_json)try{t=JSON.parse(e.checks_json)}catch{t=null}let n=Array.isArray(t)?t:Array.isArray(t?.checks)?t.checks:[],r=!Array.isArray(t)&&t?.snapshot?t.snapshot:null;return{id:e.id,runner:e.runner||`browser`,language:e.language||null,stdout:e.stdout||``,stderr:e.stderr||``,exitCode:e.exit_code??null,durationMs:e.duration_ms??null,createdAt:e.created_at||``,checks:n,snapshot:r,hash:r?.hash||null}}var j=/^[a-zA-Z]:[\\/]/,M=/[\u0000-\u001f\u007f]/,N=/\\/;function Oe(e){if(typeof e!=`string`)return!1;let t=e.trim();if(!t||t.length>512||M.test(t)||t.startsWith(`/`)||t.startsWith(`~`)||j.test(t)||N.test(t)||t.endsWith(`/`))return!1;let n=t.split(`/`);for(let e of n)if(e===``||e===`.`||e===`..`)return!1;return!0}function ke(e){return String(e||``).normalize(`NFKD`).replace(/[\u0300-\u036f]/g,``).toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).slice(0,80)||`workspace`}var Ae=(0,x.lazy)(()=>a(()=>import(`./Editor-Cw9j3cnp.js`),__vite__mapDeps([0,1,2,3,4,5,6]),import.meta.url)),je={stdout:``,stderr:``,checks:[],rows:null,preview:null,exitCode:null,durationMs:null,runner:null,statusText:``,timedOut:!1,aborted:!1,outputTruncated:!1};function Me(){let[e,t]=(0,x.useState)(()=>typeof window<`u`&&!!window.matchMedia?.(`(prefers-color-scheme: dark)`).matches);return(0,x.useEffect)(()=>{if(typeof window>`u`||!window.matchMedia)return;let e=window.matchMedia(`(prefers-color-scheme: dark)`),n=()=>t(e.matches);return e.addEventListener?.(`change`,n),()=>e.removeEventListener?.(`change`,n)},[]),e}function P(e){return Object.fromEntries(e.map(e=>[e.path,e.content]))}function Ne(e){return/\.[a-z0-9]+$/i.test(e)?e:`${e}.js`}function F({lesson:e,course:t}){let a=r(),[u]=n(),d=Me(),m=t?.id||null,h=ke(t?.title||m||`workspace`),[v,C]=(0,x.useState)([]),[w,T]=(0,x.useState)(null),[ye,E]=(0,x.useState)(!1),[D,O]=(0,x.useState)(null),[k,A]=(0,x.useState)(null),[j,M]=(0,x.useState)(null),[N,F]=(0,x.useState)([]),[Pe,I]=(0,x.useState)(!1),[L,R]=(0,x.useState)(null),[z,Fe]=(0,x.useState)(()=>!Ce(u)),[Ie,B]=(0,x.useState)([]),[V,Le]=(0,x.useState)(null),[H,U]=(0,x.useState)(null),W=(0,x.useRef)(null),G=(0,x.useRef)({...je}),K=(0,x.useRef)(null),q=(0,x.useRef)(v),J=(0,x.useRef)(new Set),Re=(0,x.useRef)(null),Y=(0,x.useRef)(new Map),ze=(0,x.useRef)(null),Be=(0,x.useRef)(e?.content_md||``);q.current=v;let Ve=(0,x.useRef)(z);Ve.current=z;let He=(0,x.useCallback)(()=>{typeof requestAnimationFrame>`u`?A({...G.current}):K.current||=requestAnimationFrame(()=>{K.current=null,A({...G.current})})},[]),X=(0,x.useCallback)(async()=>{try{let t=await f(e.id);F(t.map(De))}catch{F([])}},[e?.id]);(0,x.useEffect)(()=>{let n=!0;return E(!1),Y.current=new Map,J.current=new Set,(async()=>{let r=[],a=!1,c=[],l=null;try{let[n,i,o]=await Promise.all([ee(e.id),f(e.id).catch(()=>[]),s(e.id).catch(()=>null)]);for(let e of n)Y.current.set(e.path,e.id);Be.current=o?.content_md||e?.content_md||``,{files:r,persist:a,stalePaths:c,unsupportedSkeleton:l}=ae({lesson:e,course:t,version:o,rows:n,runCount:i.length})}catch{({files:r,unsupportedSkeleton:l}=ue(e,t))}if(a)for(let t of r)try{let n=await i({courseId:m,lessonId:e.id,path:t.path,language:t.language,content:t.content});Y.current.set(t.path,n.id)}catch{}for(let t of c)try{await o({lessonId:e.id,path:t}),Y.current.delete(t)}catch{}n&&(U(l),C(r),T(r[0]?.path||null),E(!0),g(e.id,{language:r[0]?.language||null,entry:r[0]?.path||null,files:P(r)}))})(),X(),()=>{n=!1,K.current&&typeof cancelAnimationFrame<`u`&&cancelAnimationFrame(K.current),le(e.id)}},[e?.id]);let Z=ge(w?y(w):null);(0,x.useEffect)(()=>{if(!Z||Z.backend!==`local`||L)return;let e=!0;return pe(u).then(t=>e&&R(t)).catch(()=>e&&R(null)),()=>{e=!1}},[w,Z?.id,L]);let Ue=(0,x.useCallback)(async()=>{let t=[...J.current];J.current.clear();for(let n of t){let t=q.current.find(e=>e.path===n);if(t)try{let r=await i({courseId:m,lessonId:e.id,path:n,language:t.language,content:t.content});Y.current.set(n,r.id)}catch{}}},[m,e?.id]),We=(0,x.useCallback)(e=>{J.current.add(e),clearTimeout(Re.current),Re.current=setTimeout(Ue,1e3)},[Ue]),Ge=(0,x.useCallback)((e,t,{persist:n=!0}={})=>{C(n=>n.map(n=>n.path===e?{...n,content:t}:n)),n&&We(e)},[We]);(0,x.useEffect)(()=>{if(!w)return;let t=q.current.find(e=>e.path===w);g(e.id,{language:t?.language||null,entry:w,files:P(q.current)})},[w,JSON.stringify(v)]);let Ke=(0,x.useCallback)(e=>{let t=G.current;e.stream===`stdout`?t.stdout+=e.text:e.stream===`stderr`?t.stderr+=e.text:e.stream===`status`&&(t.statusText=e.text),He()},[He]),qe=(0,x.useCallback)(async n=>{if(D||!q.current.length)return;let r=q.current,i=r.find(e=>e.path===w)||r[0],o=me(i?.language)||fe(t)||y(i?.path)||`javascript`,s=b(o,{toolchains:L}).kind;if(Te({runnerKind:s,acknowledged:Ve.current}))M(Object.assign(Error(a(`runnerNotice.notice.blocked`)),{hint:a(`runnerNotice.notice.blockedHint`)}));else{M(null),O(n),W.current=new AbortController,G.current={...je},A({...G.current}),B([]);try{let t=await he({language:o,files:P(r),entry:i?.path,courseSlug:h,settings:u,signal:W.current.signal,onOutput:Ke});if(G.current={...G.current,...t},A({...G.current}),!t.aborted){B(_(t.checks??[],e=>a(`revision.workspace.fallbackQuestion`,{label:e.label})));let n=Ee({checks:t.checks,files:P(r),entry:i?.path,language:o}),s=se(ze),c=await ne({lessonId:e.id,fileId:Y.current.get(i?.path)||null,runner:t.runner,language:o,stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode,checks:n,durationMs:t.durationMs,revisionOf:s});Le(c?.id??null),await X()}}catch(e){e?.code===`aborted`||e?.name===`AbortError`?(G.current.aborted=!0,A({...G.current})):M(e)}finally{O(null),W.current=null}}},[w,t,h,e?.id,Ke,X,D,u,a,L]),Je=(0,x.useCallback)(()=>{W.current?.abort()},[]),Ye=(0,x.useCallback)(()=>{we(u),Fe(!0)},[u]),Xe=(0,x.useCallback)(()=>{oe(ze,re(V)),M(null)},[V]),Ze=(0,x.useCallback)(async()=>{let t=window.prompt(a(`workspace.newFileName`));if(!t)return;let n=Ne(t.trim());if(!Oe(n)){M(Object.assign(Error(a(`workspace.invalidFileName`)),{hint:a(`workspace.invalidFileHint`)}));return}if(q.current.some(e=>e.path===n)){T(n);return}let r=y(n),o=[...q.current,{path:n,content:``,language:r}];C(o),T(n);try{let t=await i({courseId:m,lessonId:e.id,path:n,language:r,content:``});Y.current.set(n,t.id)}catch{}},[m,e?.id]),Qe=(0,x.useCallback)(async t=>{let n=window.prompt(a(`workspace.renameTo`),t);if(!n||n.trim()===t)return;let r=n.trim();if(!Oe(r)||q.current.some(e=>e.path===r)){M(Object.assign(Error(a(`workspace.invalidOrDuplicate`)),{hint:a(`workspace.invalidOrDuplicateHint`)}));return}let s=q.current.find(e=>e.path===t);if(!s)return;let c=y(r)||s.language;C(e=>e.map(e=>e.path===t?{...e,path:r,language:c}:e)),w===t&&T(r);try{await i({courseId:m,lessonId:e.id,path:r,language:c,content:s.content}),await o({lessonId:e.id,path:t})}catch{}},[w,m,e?.id]),$e=(0,x.useCallback)(async t=>{if(q.current.length<=1||!window.confirm(a(`workspace.deleteFileConfirm`,{path:t})))return;let n=q.current.filter(e=>e.path!==t);C(n),w===t&&T(n[0]?.path||null);try{await o({lessonId:e.id,path:t})}catch{}},[w,m,e?.id]),et=(0,x.useCallback)(async()=>{if(!window.confirm(a(`workspace.resetConfirm`)))return;let n=ce({lesson:{...e,content_md:Be.current||e?.content_md||``},course:t,storedPaths:[...Y.current.keys()]});for(let t of n.deletePaths){J.current.delete(t);try{await o({lessonId:e.id,path:t}),Y.current.delete(t)}catch{}}if(U(n.unsupportedSkeleton),C(n.files),T(n.files[0]?.path||null),n.persist)for(let t of n.files)try{let n=await i({courseId:m,lessonId:e.id,path:t.path,language:t.language,content:t.content});Y.current.set(t.path,n.id)}catch{}},[t,m,e]),tt=(0,x.useCallback)(async t=>{let n=t.snapshot?.files;if(!n)return;let r=Object.entries(n).map(([e,t])=>({path:e,content:String(t??``),language:y(e)}));C(r),T(r[0]?.path||null),I(!1);for(let t of r)try{let n=await i({courseId:m,lessonId:e.id,path:t.path,language:t.language,content:t.content});Y.current.set(t.path,n.id)}catch{}},[m,e?.id]),Q=v.find(e=>e.path===w)||v[0]||null,$=b(Q?.language,{toolchains:L}),nt=V&&(k?.checks?.length??0)>0&&!ie(k?.checks)?Xe:null,rt=(0,x.useMemo)(()=>N.map((e,t)=>({id:e.id,label:a(`revision.history.attempt`,{n:t+1}),criteria:_(e.checks??[],e=>a(`revision.workspace.fallbackQuestion`,{label:e.label}))})),[N,a]);return ye?(0,S.jsxs)(p,{className:`space-y-3`,children:[(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,S.jsx)(`h2`,{className:`font-medium`,children:a(`workspace.title`)}),$.kind===`local`&&!$.ready&&(0,S.jsx)(`span`,{className:`text-xs text-amber-600 dark:text-amber-400`,children:$.command?a(`workspace.needsCommandShort`,{command:$.command}):a(`workspace.needsServerShort`)})]}),(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,S.jsx)(l,{size:`sm`,onClick:()=>qe(`run`),disabled:!!D||!v.length,children:a(D===`run`?`workspace.running`:`workspace.run`)}),(0,S.jsx)(l,{size:`sm`,variant:`secondary`,onClick:()=>qe(`check`),disabled:!!D||!v.length,children:a(D===`check`?`workspace.check`:`workspace.checkButton`)}),D&&(0,S.jsx)(l,{size:`sm`,variant:`ghost`,onClick:Je,children:a(`workspace.stop`)}),(0,S.jsxs)(l,{size:`sm`,variant:`ghost`,onClick:()=>I(e=>!e),children:[a(`workspace.history`),N.length?` (${N.length})`:``]}),(0,S.jsx)(l,{size:`sm`,variant:`ghost`,onClick:et,children:a(`workspace.reset`)})]})]}),(0,S.jsx)(ve,{runnerInfo:$,acknowledged:z,onAcknowledge:Ye}),H?(0,S.jsx)(Se,{skeleton:H}):(0,S.jsx)(_e,{files:v,activePath:Q?.path,onSelect:T,onAdd:Ze,onRename:Qe,onDelete:$e}),Q?(0,S.jsx)(x.Suspense,{fallback:(0,S.jsxs)(`div`,{className:`flex h-64 items-center justify-center text-sm text-neutral-500`,children:[(0,S.jsx)(c,{}),` `,a(`workspace.loadingEditor`)]}),children:(0,S.jsx)(Ae,{value:Q.content,language:Q.language,dark:d,onChange:e=>Ge(Q.path,e)})}):null,j?(0,S.jsx)(te,{error:j,onDismiss:()=>M(null)}):null,(0,S.jsx)(be,{output:k,runnerInfo:$,criteria:Ie,criteriaTitle:a(`revision.workspace.criteriaTitle`),reviseHint:a(`revision.workspace.reviseHint`),onRevise:nt}),rt.length>0?(0,S.jsx)(de,{attempts:rt,title:a(`revision.history.title`)}):null,Pe?(0,S.jsx)(`div`,{className:`border-t border-neutral-200 pt-3 dark:border-neutral-800`,children:(0,S.jsx)(xe,{runs:N,onRestore:tt,onClose:()=>I(!1)})}):null]}):(0,S.jsxs)(p,{className:`flex items-center gap-2 text-sm text-neutral-500`,children:[(0,S.jsx)(c,{}),` `,a(`workspace.loading`)]})}export{F as CodeWorkspace};
@@ -1 +1 @@
1
- import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{t}from"./react-B8SKf8RM.js";import{f as n}from"./settings-DhwuyNPU.js";import{d as r,l as i}from"./errors-BZa_CNHL.js";import{Ct as a,Dt as o,J as s,Lt as c,Mt as l,Pt as u,Q as d,Rt as f,U as p,Y as m,_t as h,f as g,g as _,h as v,i as y,p as b,t as x,u as S,zt as C}from"./index-DioXTZVc.js";import{a as w,d as T,o as E,t as D}from"./capstone-Amn6Hztq.js";import{n as O}from"./course-export-DpaOTT3a.js";import{t as k}from"./Progress-CRc_xEWC.js";var A=e(t(),1),j=_();function M({course:e,capstone:t,generating:n=!1,error:r=null,onGenerate:i,onDismissError:a}){let o=c(),s=E(e),l=w(e),u=D(t?.artifact);return(0,j.jsxs)(b,{className:`space-y-3`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,j.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,j.jsx)(`h2`,{className:`font-semibold`,children:o(`capstone.cardTitle`)}),s?(0,j.jsx)(v,{tone:`success`,children:o(`capstone.unlocked`)}):(0,j.jsx)(v,{tone:`neutral`,children:o(`capstone.locked`)})]}),(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[t&&s&&(0,j.jsx)(f,{to:`/course/${e.id}/capstone`,children:(0,j.jsx)(g,{size:`sm`,children:o(`capstone.start`)})}),!t&&s&&(0,j.jsx)(g,{size:`sm`,onClick:i,disabled:n,children:o(n?`capstone.generating`:`capstone.generate`)})]})]}),u&&(0,j.jsxs)(`p`,{className:`text-sm text-neutral-600 dark:text-neutral-300`,children:[(0,j.jsxs)(`span`,{className:`font-medium`,children:[o(`capstone.yourArtifact`),`:`]}),` `,u]}),!s&&(0,j.jsxs)(`div`,{className:`space-y-1`,children:[(0,j.jsx)(k,{value:l.pct,label:o(`common.lessonsDoneShort`,{done:l.done,total:l.total})}),(0,j.jsxs)(`p`,{className:`text-xs text-neutral-500`,children:[o(`common.lessonsDone`,{done:l.done,total:l.total}),` — `,o(`capstone.lockedHint`)]})]}),!t&&!s&&(0,j.jsx)(`p`,{className:`text-sm text-neutral-500`,children:o(`capstone.readAnyway`)}),r&&(0,j.jsx)(y,{error:r,onDismiss:a})]})}function N(e){if(!e)return``;try{return new Date(e).toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`})}catch{return String(e).slice(0,10)}}function P({course:e,onClose:t,onSaved:n,t:i}){let[o,s]=(0,A.useState)(e.language||`en`),[c,l]=(0,A.useState)(!1);return(0,j.jsx)(`div`,{className:`fixed inset-0 z-30 grid place-items-center bg-black/40 p-4`,role:`dialog`,"aria-modal":`true`,"aria-label":i(`course.languageDialog.title`),children:(0,j.jsxs)(b,{className:`w-full max-w-md space-y-4`,children:[(0,j.jsx)(`h2`,{className:`font-semibold`,children:i(`course.languageDialog.title`)}),(0,j.jsx)(`p`,{className:`text-sm text-neutral-600 dark:text-neutral-300`,children:i(`course.languageDialog.body`)}),(0,j.jsx)(S,{label:i(`course.languageDialog.label`),name:`courseLanguage`,value:o,onChange:e=>s(e.target.value),children:r().map(e=>(0,j.jsx)(`option`,{value:e.code,children:e.name},e.code))}),(0,j.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,j.jsx)(g,{variant:`ghost`,onClick:t,children:i(`common.cancel`)}),(0,j.jsx)(g,{onClick:async()=>{l(!0);let t=await a(e.id,{language:o});l(!1),n(t)},disabled:c,children:i(`course.languageDialog.confirm`)})]})]})})}function F({id:e}){let t=c(),[r]=n(),[a,_]=(0,A.useState)(null),[y,S]=(0,A.useState)(null),[w,E]=(0,A.useState)(!1),[D,F]=(0,A.useState)({}),[I,L]=(0,A.useState)(!1),[R,z]=(0,A.useState)(null),[B,V]=(0,A.useState)(!1);if((0,A.useEffect)(()=>{let t=!0,n=async()=>{let n=await m(e),r=n?await s(e):null;t&&(_(n),S(r))};n().finally(()=>t&&E(!0));let r=h(e=>{[`courses`,`lessons`,`capstones`,`*`].includes(e.table)&&n().catch(()=>{})});return()=>{t=!1,r()}},[e]),(0,A.useEffect)(()=>{let e=!0,t=(a?.lessons||[]).filter(e=>e.status===`done`);return Promise.all(t.map(e=>d(e.id).then(t=>[e.id,t.reflection]))).then(t=>{e&&F(Object.fromEntries(t.filter(([,e])=>e&&e.hardest)))}).catch(()=>{}),()=>{e=!1}},[a]),!w)return(0,j.jsx)(`p`,{className:`text-sm text-neutral-500`,children:t(`common.loading`)});if(!a)return(0,j.jsx)(x,{title:t(`course.notFound.title`),description:t(`course.notFound.description`),action:(0,j.jsx)(f,{to:`/`,children:(0,j.jsx)(g,{variant:`secondary`,children:t(`course.notFound.back`)})})});let H=l(a),U=o.find(e=>e.id===a.kind)?.label;return(0,j.jsxs)(`div`,{className:`space-y-5`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[(0,j.jsxs)(`div`,{className:`min-w-0 space-y-2`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,j.jsx)(`h1`,{className:`text-xl font-semibold`,children:a.title}),(0,j.jsx)(v,{tone:`neutral`,children:a.level}),U&&(0,j.jsx)(v,{tone:`accent`,children:U}),(0,j.jsx)(v,{tone:`neutral`,children:i(a.language)}),a.status===`completed`&&(0,j.jsx)(v,{tone:`success`,children:t(`course.complete`)})]}),a.goal&&(0,j.jsx)(`p`,{className:`text-sm text-neutral-600 dark:text-neutral-300`,children:t(`course.goal`,{goal:a.goal})}),a.description&&(0,j.jsx)(`p`,{className:`text-sm text-neutral-500`,children:a.description}),(0,j.jsx)(k,{value:H.pct,label:t(`common.lessonsDoneShort`,{done:H.done,total:H.total})}),(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:t(`common.lessonsDone`,{done:H.done,total:H.total})})]}),(0,j.jsxs)(`div`,{className:`flex shrink-0 items-center gap-2`,children:[(0,j.jsx)(g,{variant:`secondary`,size:`sm`,onClick:()=>V(!0),children:t(`course.changeLanguage`)}),(0,j.jsx)(g,{variant:`secondary`,size:`sm`,onClick:async()=>{try{await O(a)}catch{}},children:t(`course.exportMd`)}),(0,j.jsx)(g,{variant:`danger`,size:`sm`,onClick:async()=>{window.confirm(t(`course.deleteConfirm`,{title:a.title}))&&(await p(a.id),C(`/`))},children:t(`course.delete`)})]})]}),(0,j.jsx)(M,{course:a,capstone:y,generating:I,error:R,onGenerate:async()=>{L(!0),z(null);try{let e=await T({course:a,artifact:y?.artifact,settings:r});S(e)}catch(e){z(e)}finally{L(!1)}},onDismissError:()=>z(null)}),(0,j.jsx)(`div`,{className:`space-y-2`,children:a.lessons.map(e=>{let n=D[e.id],r=t(`course.lessonLabel.${e.status===`done`?`done`:e.status===`active`?`active`:`todo`}`);return(0,j.jsxs)(b,{className:`flex flex-wrap items-center justify-between gap-3 py-3`,children:[(0,j.jsxs)(`div`,{className:`flex min-w-0 items-start gap-3`,children:[(0,j.jsx)(`span`,{"aria-hidden":`true`,className:`mt-0.5`,children:u(e.status)}),(0,j.jsxs)(`div`,{className:`min-w-0`,children:[(0,j.jsxs)(`p`,{className:`font-medium`,children:[e.position,`. `,e.title]}),e.summary&&(0,j.jsx)(`p`,{className:`text-sm text-neutral-500`,children:e.summary}),e.status===`done`&&e.completed_at&&(0,j.jsx)(`p`,{className:`mt-1 text-xs text-neutral-400`,children:t(`course.completedOn`,{date:N(e.completed_at)})}),n?.hardest&&(0,j.jsx)(`p`,{className:`mt-1 text-xs text-neutral-500 italic`,children:t(`course.hardest`,{text:n.hardest})})]})]}),(0,j.jsx)(f,{to:`/course/${a.id}/lesson/${e.id}`,children:(0,j.jsx)(g,{variant:e.status===`active`?`primary`:`secondary`,size:`sm`,children:r})})]},e.id)})}),B&&(0,j.jsx)(P,{course:a,t,onClose:()=>V(!1),onSaved:e=>{_(t=>({...t,...e})),V(!1)}})]})}export{F as Course};
1
+ import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{t}from"./react-B8SKf8RM.js";import{f as n}from"./settings-DhwuyNPU.js";import{d as r,l as i}from"./errors-BZa_CNHL.js";import{Ct as a,Dt as o,J as s,Lt as c,Mt as l,Pt as u,Q as d,Rt as f,U as p,Y as m,_t as h,f as g,g as _,h as v,i as y,p as b,t as x,u as S,zt as C}from"./index-CS8XPYbB.js";import{a as w,d as T,o as E,t as D}from"./capstone-DhwBeNqk.js";import{n as O}from"./course-export-C8jSPuda.js";import{t as k}from"./Progress-2rS19Fur.js";var A=e(t(),1),j=_();function M({course:e,capstone:t,generating:n=!1,error:r=null,onGenerate:i,onDismissError:a}){let o=c(),s=E(e),l=w(e),u=D(t?.artifact);return(0,j.jsxs)(b,{className:`space-y-3`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,j.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,j.jsx)(`h2`,{className:`font-semibold`,children:o(`capstone.cardTitle`)}),s?(0,j.jsx)(v,{tone:`success`,children:o(`capstone.unlocked`)}):(0,j.jsx)(v,{tone:`neutral`,children:o(`capstone.locked`)})]}),(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[t&&s&&(0,j.jsx)(f,{to:`/course/${e.id}/capstone`,children:(0,j.jsx)(g,{size:`sm`,children:o(`capstone.start`)})}),!t&&s&&(0,j.jsx)(g,{size:`sm`,onClick:i,disabled:n,children:o(n?`capstone.generating`:`capstone.generate`)})]})]}),u&&(0,j.jsxs)(`p`,{className:`text-sm text-neutral-600 dark:text-neutral-300`,children:[(0,j.jsxs)(`span`,{className:`font-medium`,children:[o(`capstone.yourArtifact`),`:`]}),` `,u]}),!s&&(0,j.jsxs)(`div`,{className:`space-y-1`,children:[(0,j.jsx)(k,{value:l.pct,label:o(`common.lessonsDoneShort`,{done:l.done,total:l.total})}),(0,j.jsxs)(`p`,{className:`text-xs text-neutral-500`,children:[o(`common.lessonsDone`,{done:l.done,total:l.total}),` — `,o(`capstone.lockedHint`)]})]}),!t&&!s&&(0,j.jsx)(`p`,{className:`text-sm text-neutral-500`,children:o(`capstone.readAnyway`)}),r&&(0,j.jsx)(y,{error:r,onDismiss:a})]})}function N(e){if(!e)return``;try{return new Date(e).toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`})}catch{return String(e).slice(0,10)}}function P({course:e,onClose:t,onSaved:n,t:i}){let[o,s]=(0,A.useState)(e.language||`en`),[c,l]=(0,A.useState)(!1);return(0,j.jsx)(`div`,{className:`fixed inset-0 z-30 grid place-items-center bg-black/40 p-4`,role:`dialog`,"aria-modal":`true`,"aria-label":i(`course.languageDialog.title`),children:(0,j.jsxs)(b,{className:`w-full max-w-md space-y-4`,children:[(0,j.jsx)(`h2`,{className:`font-semibold`,children:i(`course.languageDialog.title`)}),(0,j.jsx)(`p`,{className:`text-sm text-neutral-600 dark:text-neutral-300`,children:i(`course.languageDialog.body`)}),(0,j.jsx)(S,{label:i(`course.languageDialog.label`),name:`courseLanguage`,value:o,onChange:e=>s(e.target.value),children:r().map(e=>(0,j.jsx)(`option`,{value:e.code,children:e.name},e.code))}),(0,j.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,j.jsx)(g,{variant:`ghost`,onClick:t,children:i(`common.cancel`)}),(0,j.jsx)(g,{onClick:async()=>{l(!0);let t=await a(e.id,{language:o});l(!1),n(t)},disabled:c,children:i(`course.languageDialog.confirm`)})]})]})})}function F({id:e}){let t=c(),[r]=n(),[a,_]=(0,A.useState)(null),[y,S]=(0,A.useState)(null),[w,E]=(0,A.useState)(!1),[D,F]=(0,A.useState)({}),[I,L]=(0,A.useState)(!1),[R,z]=(0,A.useState)(null),[B,V]=(0,A.useState)(!1);if((0,A.useEffect)(()=>{let t=!0,n=async()=>{let n=await m(e),r=n?await s(e):null;t&&(_(n),S(r))};n().finally(()=>t&&E(!0));let r=h(e=>{[`courses`,`lessons`,`capstones`,`*`].includes(e.table)&&n().catch(()=>{})});return()=>{t=!1,r()}},[e]),(0,A.useEffect)(()=>{let e=!0,t=(a?.lessons||[]).filter(e=>e.status===`done`);return Promise.all(t.map(e=>d(e.id).then(t=>[e.id,t.reflection]))).then(t=>{e&&F(Object.fromEntries(t.filter(([,e])=>e&&e.hardest)))}).catch(()=>{}),()=>{e=!1}},[a]),!w)return(0,j.jsx)(`p`,{className:`text-sm text-neutral-500`,children:t(`common.loading`)});if(!a)return(0,j.jsx)(x,{title:t(`course.notFound.title`),description:t(`course.notFound.description`),action:(0,j.jsx)(f,{to:`/`,children:(0,j.jsx)(g,{variant:`secondary`,children:t(`course.notFound.back`)})})});let H=l(a),U=o.find(e=>e.id===a.kind)?.label;return(0,j.jsxs)(`div`,{className:`space-y-5`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-3`,children:[(0,j.jsxs)(`div`,{className:`min-w-0 space-y-2`,children:[(0,j.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,j.jsx)(`h1`,{className:`text-xl font-semibold`,children:a.title}),(0,j.jsx)(v,{tone:`neutral`,children:a.level}),U&&(0,j.jsx)(v,{tone:`accent`,children:U}),(0,j.jsx)(v,{tone:`neutral`,children:i(a.language)}),a.status===`completed`&&(0,j.jsx)(v,{tone:`success`,children:t(`course.complete`)})]}),a.goal&&(0,j.jsx)(`p`,{className:`text-sm text-neutral-600 dark:text-neutral-300`,children:t(`course.goal`,{goal:a.goal})}),a.description&&(0,j.jsx)(`p`,{className:`text-sm text-neutral-500`,children:a.description}),(0,j.jsx)(k,{value:H.pct,label:t(`common.lessonsDoneShort`,{done:H.done,total:H.total})}),(0,j.jsx)(`p`,{className:`text-xs text-neutral-500`,children:t(`common.lessonsDone`,{done:H.done,total:H.total})})]}),(0,j.jsxs)(`div`,{className:`flex shrink-0 items-center gap-2`,children:[(0,j.jsx)(g,{variant:`secondary`,size:`sm`,onClick:()=>V(!0),children:t(`course.changeLanguage`)}),(0,j.jsx)(g,{variant:`secondary`,size:`sm`,onClick:async()=>{try{await O(a)}catch{}},children:t(`course.exportMd`)}),(0,j.jsx)(g,{variant:`danger`,size:`sm`,onClick:async()=>{window.confirm(t(`course.deleteConfirm`,{title:a.title}))&&(await p(a.id),C(`/`))},children:t(`course.delete`)})]})]}),(0,j.jsx)(M,{course:a,capstone:y,generating:I,error:R,onGenerate:async()=>{L(!0),z(null);try{let e=await T({course:a,artifact:y?.artifact,settings:r});S(e)}catch(e){z(e)}finally{L(!1)}},onDismissError:()=>z(null)}),(0,j.jsx)(`div`,{className:`space-y-2`,children:a.lessons.map(e=>{let n=D[e.id],r=t(`course.lessonLabel.${e.status===`done`?`done`:e.status===`active`?`active`:`todo`}`);return(0,j.jsxs)(b,{className:`flex flex-wrap items-center justify-between gap-3 py-3`,children:[(0,j.jsxs)(`div`,{className:`flex min-w-0 items-start gap-3`,children:[(0,j.jsx)(`span`,{"aria-hidden":`true`,className:`mt-0.5`,children:u(e.status)}),(0,j.jsxs)(`div`,{className:`min-w-0`,children:[(0,j.jsxs)(`p`,{className:`font-medium`,children:[e.position,`. `,e.title]}),e.summary&&(0,j.jsx)(`p`,{className:`text-sm text-neutral-500`,children:e.summary}),e.status===`done`&&e.completed_at&&(0,j.jsx)(`p`,{className:`mt-1 text-xs text-neutral-400`,children:t(`course.completedOn`,{date:N(e.completed_at)})}),n?.hardest&&(0,j.jsx)(`p`,{className:`mt-1 text-xs text-neutral-500 italic`,children:t(`course.hardest`,{text:n.hardest})})]})]}),(0,j.jsx)(f,{to:`/course/${a.id}/lesson/${e.id}`,children:(0,j.jsx)(g,{variant:e.status===`active`?`primary`:`secondary`,size:`sm`,children:r})})]},e.id)})}),B&&(0,j.jsx)(P,{course:a,t,onClose:()=>V(!1),onSaved:e=>{_(t=>({...t,...e})),V(!1)}})]})}export{F as Course};