ronin-skillforce 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/README.md +225 -2
- package/bin/cli.js +811 -0
- package/bin/commands/check.js +298 -0
- package/bin/commands/create.js +169 -0
- package/bin/commands/doctor.js +392 -0
- package/bin/commands/import.js +557 -0
- package/bin/commands/next.js +125 -0
- package/bin/commands/review.js +207 -0
- package/bin/commands/status.js +114 -0
- package/bin/commands/studio.js +497 -0
- package/bin/commands/trail.js +211 -0
- package/bin/commands/web.js +350 -0
- package/bin/course-reader.js +611 -0
- package/bin/node-version.js +60 -0
- package/bin/platforms/_shared.js +211 -0
- package/bin/platforms/claude.js +104 -0
- package/bin/platforms/cursor.js +49 -0
- package/bin/platforms/gemini.js +65 -0
- package/bin/platforms/opencode.js +95 -0
- package/bin/registry-helpers.js +504 -0
- package/bin/static-server.js +153 -0
- package/bin/studio-store.js +94 -0
- package/bin/sync-shared.sh +5 -0
- package/package.json +91 -4
- package/plugin.json +139 -0
- package/shared/SKILL.md +568 -0
- package/shared/agents/coach.md +225 -0
- package/shared/agents/navigator.md +215 -0
- package/shared/agents/professor.md +372 -0
- package/shared/agents/researcher.md +181 -0
- package/shared/agents/spotter.md +129 -0
- package/shared/commands/professor/archive.md +103 -0
- package/shared/commands/professor/capstone-review.md +79 -0
- package/shared/commands/professor/capstone.md +34 -0
- package/shared/commands/professor/discuss.md +18 -0
- package/shared/commands/professor/done.md +44 -0
- package/shared/commands/professor/export.md +69 -0
- package/shared/commands/professor/hint.md +108 -0
- package/shared/commands/professor/navigator.md +67 -0
- package/shared/commands/professor/new-topic.md +73 -0
- package/shared/commands/professor/next.md +174 -0
- package/shared/commands/professor/note.md +63 -0
- package/shared/commands/professor/onboard.md +95 -0
- package/shared/commands/professor/progress.md +46 -0
- package/shared/commands/professor/publish.md +93 -0
- package/shared/commands/professor/quiz.md +27 -0
- package/shared/commands/professor/recall.md +74 -0
- package/shared/commands/professor/review.md +43 -0
- package/shared/commands/professor/schedule.md +75 -0
- package/shared/commands/professor/skill-export.md +87 -0
- package/shared/commands/professor/spotter.md +76 -0
- package/shared/commands/professor/stuck.md +27 -0
- package/shared/commands/professor/switch.md +50 -0
- package/shared/commands/professor/syllabus.md +9 -0
- package/shared/commands/professor/template-export.md +91 -0
- package/shared/commands/professor/template-import.md +111 -0
- package/shared/commands/professor/worktrees.md +58 -0
- package/shared/hooks/pre-compact.js +232 -0
- package/studio/README.md +313 -0
- package/studio/dist/assets/BetaReportPanel-8NrDLiPm.js +1 -0
- package/studio/dist/assets/Capstone-Cv9kH6LY.js +6 -0
- package/studio/dist/assets/CodeWorkspace-BwCEINWo.js +2 -0
- package/studio/dist/assets/Course-BJ_hafUP.js +1 -0
- package/studio/dist/assets/Editor-CV0mNhlz.js +53 -0
- package/studio/dist/assets/Home-C1ry89ak.js +1 -0
- package/studio/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/studio/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/studio/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/studio/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/studio/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/studio/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/studio/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/studio/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/studio/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/studio/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/studio/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/studio/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/studio/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/studio/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/studio/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/studio/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/studio/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/studio/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/studio/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/studio/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/studio/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/studio/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/studio/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/studio/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/studio/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/studio/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/studio/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/studio/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/studio/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/studio/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/studio/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/studio/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/studio/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/studio/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/studio/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/studio/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/studio/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/studio/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/studio/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/studio/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/studio/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/studio/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/studio/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/studio/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/studio/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/studio/dist/assets/Lesson-2e9TD9yL.js +2 -0
- package/studio/dist/assets/NewCourse-BZeOg2xn.js +952 -0
- package/studio/dist/assets/Progress-CRc_xEWC.js +1 -0
- package/studio/dist/assets/Review-6QEbHEfk.js +1 -0
- package/studio/dist/assets/Settings-NFnqVQui.js +1 -0
- package/studio/dist/assets/TutorPanel-DXQ6Z3BY.js +123 -0
- package/studio/dist/assets/abnfDiagram-WEYOIA3C-qeSjKlGM.js +1 -0
- package/studio/dist/assets/anthropic-D7NiQCUH.js +15 -0
- package/studio/dist/assets/arc-Y1ARJVZ4.js +1 -0
- package/studio/dist/assets/architecture-WOLXFQ4H-COG-m35l.js +1 -0
- package/studio/dist/assets/architectureDiagram-ZHVYKT53-VO7uKoeD.js +36 -0
- package/studio/dist/assets/array-BifhSqXX.js +1 -0
- package/studio/dist/assets/blockDiagram-RJAE7QA3-BGJF_qiL.js +140 -0
- package/studio/dist/assets/bridge-BTh0AeNX.js +1 -0
- package/studio/dist/assets/c4Diagram-XDPPPE54-C-S10RgU.js +38 -0
- package/studio/dist/assets/capstone-Amn6Hztq.js +135 -0
- package/studio/dist/assets/card-store-BrbrtX9w.js +1 -0
- package/studio/dist/assets/channel-SJiUQu_N.js +1 -0
- package/studio/dist/assets/chunk-2E7WHVMD-fv-iqTyC.js +88 -0
- package/studio/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/studio/dist/assets/chunk-4EMNKR2T-CY9IZrgv.js +1 -0
- package/studio/dist/assets/chunk-55XCU76K-DyTZz7v_.js +1 -0
- package/studio/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/studio/dist/assets/chunk-7S6XSTFO-BNMzTLRW.js +2 -0
- package/studio/dist/assets/chunk-AQDTSKZB-CEYANohH.js +72 -0
- package/studio/dist/assets/chunk-DSNLSHJZ-CDk5EXjH.js +129 -0
- package/studio/dist/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
- package/studio/dist/assets/chunk-HAGFOTED-hNAi1zh_.js +62 -0
- package/studio/dist/assets/chunk-HNE4Q36P-COJnSYoZ.js +1 -0
- package/studio/dist/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
- package/studio/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/studio/dist/assets/chunk-NGNAAXSQ-C2Wy9Xmz.js +136 -0
- package/studio/dist/assets/chunk-NQOKRVIF-BU6KVxRr.js +213 -0
- package/studio/dist/assets/chunk-UHW7PFBP-DYvxL9JG.js +1 -0
- package/studio/dist/assets/chunk-VQ5W62QI-CuRfk65j.js +1 -0
- package/studio/dist/assets/chunk-WQQL4CDK-KaG7x-Mb.js +10 -0
- package/studio/dist/assets/chunk-XXDRQBXY-CnbRkih_.js +1 -0
- package/studio/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/studio/dist/assets/chunk-YZO67HFG-DbuqIZmk.js +1 -0
- package/studio/dist/assets/chunk-ZAUX2LTX-bk4ivUmc.js +1 -0
- package/studio/dist/assets/chunk-ZCHMQSOR-B_LElfwh.js +2 -0
- package/studio/dist/assets/classDiagram-v2-4MYWR3UA-DtCJ6H_X.js +217 -0
- package/studio/dist/assets/cose-bilkent-JH36ORCC-DMBAZFnj.js +1 -0
- package/studio/dist/assets/course-export-DpaOTT3a.js +1 -0
- package/studio/dist/assets/cynefin-EF2NZ3EQ-D9btHJvU.js +1 -0
- package/studio/dist/assets/cynefinDiagram-WF24UDRP-CsFJuv27.js +62 -0
- package/studio/dist/assets/cytoscape.esm-CHBj4VkZ.js +321 -0
- package/studio/dist/assets/dagre-NK4GIZVX-Cg1Duec7.js +4 -0
- package/studio/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/studio/dist/assets/diagram-CBK3MWTC-_KU2m5gd.js +24 -0
- package/studio/dist/assets/diagram-I5XIIV2D-5RaBrwUA.js +24 -0
- package/studio/dist/assets/diagram-ODIL2UCW-C0VKxoD3.js +30 -0
- package/studio/dist/assets/diagram-PFBEJUXE-BaHcZEP2.js +3 -0
- package/studio/dist/assets/diagram-RJA3I4VV-cwSAZ90p.js +41 -0
- package/studio/dist/assets/diagram-TYUNFSNR-BJImxCEN.js +200 -0
- package/studio/dist/assets/dist-CumnGVmJ.js +1 -0
- package/studio/dist/assets/ebnfDiagram-V4P3TTPT-OQQLRXcm.js +1 -0
- package/studio/dist/assets/elk-QONTBCTQ-BJGhQHxQ.js +27 -0
- package/studio/dist/assets/erDiagram-KYQIGQAA-D91EKSep.js +99 -0
- package/studio/dist/assets/error-BTdmRKoB.js +1 -0
- package/studio/dist/assets/errors-BZa_CNHL.js +1 -0
- package/studio/dist/assets/eventmodeling-K75KTNOO-DgdTRgnw.js +1 -0
- package/studio/dist/assets/fetch-local-DG3O3hmQ.js +4 -0
- package/studio/dist/assets/flowDiagram-IUGLLWBU-CVnJYMum.js +1 -0
- package/studio/dist/assets/ganttDiagram-R7GPNTJY-CSYLPWEI.js +292 -0
- package/studio/dist/assets/gitGraph-VSP46ZUC-D6GWaV9y.js +1 -0
- package/studio/dist/assets/gitGraphDiagram-PDYL7XHY-CaV31bvT.js +106 -0
- package/studio/dist/assets/graphlib-DS17s2tU.js +1 -0
- package/studio/dist/assets/index-CVenTTOY.css +2 -0
- package/studio/dist/assets/index-DioXTZVc.js +313 -0
- package/studio/dist/assets/info-OHQRW6UA-BN-x8GoN.js +1 -0
- package/studio/dist/assets/infoDiagram-MVDRKAX5-CIose_cy.js +2 -0
- package/studio/dist/assets/init-C-OQMol4.js +1 -0
- package/studio/dist/assets/ishikawaDiagram-HPEHV2GE-DCihSNBw.js +70 -0
- package/studio/dist/assets/journeyDiagram-BOSHW7O7-Bz3o3RIX.js +139 -0
- package/studio/dist/assets/js.worker-AD7DjksO.js +4 -0
- package/studio/dist/assets/kanban-definition-FNSA4HC5-BUyqvlFE.js +89 -0
- package/studio/dist/assets/katex-B_JcIwqj.js +257 -0
- package/studio/dist/assets/katex-BgsA2lO1.css +1 -0
- package/studio/dist/assets/line-B08T8KlK.js +1 -0
- package/studio/dist/assets/linear-C9iwaMOi.js +1 -0
- package/studio/dist/assets/mermaid-parser.core-BYwreSUy.js +7 -0
- package/studio/dist/assets/mermaid.core-DTO1oDmq.js +44 -0
- package/studio/dist/assets/mindmap-definition-6OY57UG3-BGLwKheY.js +98 -0
- package/studio/dist/assets/node.browser-BISniYn8.js +1 -0
- package/studio/dist/assets/node.browser-HQ5SKBOf.js +1 -0
- package/studio/dist/assets/ollama-De5w84tG.js +1 -0
- package/studio/dist/assets/openai-compatible-Joy1oK3L.js +1 -0
- package/studio/dist/assets/ordinal-BDEzSJ7C.js +1 -0
- package/studio/dist/assets/packet-JDAUHWVQ-CDIMjHS_.js +1 -0
- package/studio/dist/assets/path-fybaL0A-.js +1 -0
- package/studio/dist/assets/pegDiagram-ECIUJNBX-DWXm4mwS.js +1 -0
- package/studio/dist/assets/pie-XZMESJXO-CY3QQiKZ.js +1 -0
- package/studio/dist/assets/pieDiagram-GNMPY74T-M1aCnI7W.js +39 -0
- package/studio/dist/assets/python.worker-CzTrFdd9.js +24 -0
- package/studio/dist/assets/quadrantDiagram-D57K4MC3-BFFtO7U5.js +7 -0
- package/studio/dist/assets/radar-ABXABTNO-DT0W4_Xn.js +1 -0
- package/studio/dist/assets/railroad-I3PHUGI6-_VCpgZR5.js +1 -0
- package/studio/dist/assets/railroad-abnf-LNEFI6M7-DkSpQ5YY.js +1 -0
- package/studio/dist/assets/railroad-ebnf-DWYD2UWJ-BqWILdGb.js +1 -0
- package/studio/dist/assets/railroad-peg-JR7BVNR7-BB0bQL-Z.js +1 -0
- package/studio/dist/assets/railroadDiagram-Y72NRBL7-CjLKjIdJ.js +1 -0
- package/studio/dist/assets/react-B8SKf8RM.js +1 -0
- package/studio/dist/assets/rehype-katex-C-sKddsH.js +259 -0
- package/studio/dist/assets/remark-math-C-ox67hE.js +5 -0
- package/studio/dist/assets/requirementDiagram-EQYSW5RA-CnwzZqR8.js +84 -0
- package/studio/dist/assets/rolldown-runtime-COiEfhsA.js +1 -0
- package/studio/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/studio/dist/assets/sankeyDiagram-SY24JHO5-CPDugTUl.js +40 -0
- package/studio/dist/assets/schemas-BOc2YsOP.js +55 -0
- package/studio/dist/assets/sequenceDiagram-BLEHNHQU-1dLfeU9Y.js +169 -0
- package/studio/dist/assets/settings-DhwuyNPU.js +1 -0
- package/studio/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
- package/studio/dist/assets/spec-nAnsSMkw.js +1 -0
- package/studio/dist/assets/sql-wasm-C1D_RJuy.wasm +0 -0
- package/studio/dist/assets/sql.worker-D7pBHOrq.js +4 -0
- package/studio/dist/assets/src-BWF7jMDv.js +1 -0
- package/studio/dist/assets/stateDiagram-v2-A6IESKWZ-DR7CmEjj.js +291 -0
- package/studio/dist/assets/swimlanes-B3ENRKFQ-BAWB9omQ.js +1 -0
- package/studio/dist/assets/swimlanesDiagram-AYQRV4AK-qeuHru16.js +8 -0
- package/studio/dist/assets/timeline-definition-JXYKGLGB-DNkj8z77.js +120 -0
- package/studio/dist/assets/treeView-D4JQ5SDB-BA-ouhMb.js +1 -0
- package/studio/dist/assets/treemap-SAJKECNS-BrrGxsAb.js +1 -0
- package/studio/dist/assets/useStream-rdsR6A7P.js +1 -0
- package/studio/dist/assets/usecaseDiagram-WPOLBNNX-BB3D0Dt_.js +328 -0
- package/studio/dist/assets/vennDiagram-Q3Y3IDCW-BrtqtKTE.js +34 -0
- package/studio/dist/assets/wardley-7MLQ67FV-BKkemDql.js +1 -0
- package/studio/dist/assets/wardleyDiagram-IVAIDKWA-DFnI3P5z.js +78 -0
- package/studio/dist/assets/xychartDiagram-4URNHDU4-Da0DZG_q.js +7 -0
- package/studio/dist/index.html +20 -0
- package/studio/dist/preview.html +22 -0
- package/studio/migrations/0001_init.sql +188 -0
- package/studio/migrations/0002_external_ids.sql +20 -0
- package/studio/migrations/0003_course_language.sql +12 -0
- package/studio/migrations/0004_capstone.sql +51 -0
- package/studio/migrations/0005_beta_loop.sql +73 -0
- package/studio/migrations/0006_interactive_exercises.sql +49 -0
- package/studio/src/lib/activity.js +92 -0
- package/studio/src/lib/ai/anthropic.js +109 -0
- package/studio/src/lib/ai/bridge.js +126 -0
- package/studio/src/lib/ai/catalog.js +160 -0
- package/studio/src/lib/ai/config.js +70 -0
- package/studio/src/lib/ai/errors.js +95 -0
- package/studio/src/lib/ai/fetch-local.js +104 -0
- package/studio/src/lib/ai/index.js +194 -0
- package/studio/src/lib/ai/ollama.js +136 -0
- package/studio/src/lib/ai/openai-compatible.js +101 -0
- package/studio/src/lib/ai/provider-utils.js +107 -0
- package/studio/src/lib/ai/sse.js +99 -0
- package/studio/src/lib/ai/status.js +92 -0
- package/studio/src/lib/ai/useStream.js +109 -0
- package/studio/src/lib/beta/metrics.js +147 -0
- package/studio/src/lib/beta/report.js +134 -0
- package/studio/src/lib/capstone-evidence.js +758 -0
- package/studio/src/lib/capstone.js +663 -0
- package/studio/src/lib/chat-store.js +128 -0
- package/studio/src/lib/course-export.js +38 -0
- package/studio/src/lib/course.js +187 -0
- package/studio/src/lib/exercises/journal-entry.js +259 -0
- package/studio/src/lib/exercises/placement.js +31 -0
- package/studio/src/lib/exercises/registry.js +19 -0
- package/studio/src/lib/exercises/spec.js +129 -0
- package/studio/src/lib/i18n/detect.js +162 -0
- package/studio/src/lib/i18n/en/app.json +23 -0
- package/studio/src/lib/i18n/en/betaReport.json +55 -0
- package/studio/src/lib/i18n/en/capstone.json +57 -0
- package/studio/src/lib/i18n/en/common.json +25 -0
- package/studio/src/lib/i18n/en/course.json +27 -0
- package/studio/src/lib/i18n/en/data.json +35 -0
- package/studio/src/lib/i18n/en/durability.json +5 -0
- package/studio/src/lib/i18n/en/errors.json +20 -0
- package/studio/src/lib/i18n/en/exercises.json +55 -0
- package/studio/src/lib/i18n/en/externalEvidence.json +76 -0
- package/studio/src/lib/i18n/en/home.json +18 -0
- package/studio/src/lib/i18n/en/lesson.json +33 -0
- package/studio/src/lib/i18n/en/nav.json +8 -0
- package/studio/src/lib/i18n/en/newCourse.json +51 -0
- package/studio/src/lib/i18n/en/onboarding.json +35 -0
- package/studio/src/lib/i18n/en/playwrightTemplate.json +20 -0
- package/studio/src/lib/i18n/en/practice.json +79 -0
- package/studio/src/lib/i18n/en/provider.json +27 -0
- package/studio/src/lib/i18n/en/providerMeta.json +26 -0
- package/studio/src/lib/i18n/en/reflection.json +17 -0
- package/studio/src/lib/i18n/en/revision.json +52 -0
- package/studio/src/lib/i18n/en/runnerNotice.json +14 -0
- package/studio/src/lib/i18n/en/settings.json +12 -0
- package/studio/src/lib/i18n/en/storage.json +49 -0
- package/studio/src/lib/i18n/en/tutor.json +39 -0
- package/studio/src/lib/i18n/en/workspace.json +50 -0
- package/studio/src/lib/i18n/index.js +144 -0
- package/studio/src/lib/i18n/languages.js +93 -0
- package/studio/src/lib/i18n/vi/app.json +23 -0
- package/studio/src/lib/i18n/vi/betaReport.json +55 -0
- package/studio/src/lib/i18n/vi/capstone.json +57 -0
- package/studio/src/lib/i18n/vi/common.json +25 -0
- package/studio/src/lib/i18n/vi/course.json +27 -0
- package/studio/src/lib/i18n/vi/data.json +35 -0
- package/studio/src/lib/i18n/vi/durability.json +5 -0
- package/studio/src/lib/i18n/vi/errors.json +20 -0
- package/studio/src/lib/i18n/vi/exercises.json +55 -0
- package/studio/src/lib/i18n/vi/externalEvidence.json +76 -0
- package/studio/src/lib/i18n/vi/home.json +18 -0
- package/studio/src/lib/i18n/vi/lesson.json +33 -0
- package/studio/src/lib/i18n/vi/nav.json +8 -0
- package/studio/src/lib/i18n/vi/newCourse.json +51 -0
- package/studio/src/lib/i18n/vi/onboarding.json +35 -0
- package/studio/src/lib/i18n/vi/playwrightTemplate.json +20 -0
- package/studio/src/lib/i18n/vi/practice.json +79 -0
- package/studio/src/lib/i18n/vi/provider.json +27 -0
- package/studio/src/lib/i18n/vi/providerMeta.json +26 -0
- package/studio/src/lib/i18n/vi/reflection.json +17 -0
- package/studio/src/lib/i18n/vi/revision.json +52 -0
- package/studio/src/lib/i18n/vi/runnerNotice.json +14 -0
- package/studio/src/lib/i18n/vi/settings.json +12 -0
- package/studio/src/lib/i18n/vi/storage.json +49 -0
- package/studio/src/lib/i18n/vi/tutor.json +39 -0
- package/studio/src/lib/i18n/vi/workspace.json +50 -0
- package/studio/src/lib/ids.js +10 -0
- package/studio/src/lib/json.js +26 -0
- package/studio/src/lib/markdown.js +74 -0
- package/studio/src/lib/prompts/base.js +139 -0
- package/studio/src/lib/prompts/capstone.js +777 -0
- package/studio/src/lib/prompts/course.js +150 -0
- package/studio/src/lib/prompts/lesson.js +275 -0
- package/studio/src/lib/prompts/practice.js +511 -0
- package/studio/src/lib/prompts/tutor.js +509 -0
- package/studio/src/lib/repo/blocked-adapter.js +69 -0
- package/studio/src/lib/repo/events.js +239 -0
- package/studio/src/lib/repo/idb-adapter.js +226 -0
- package/studio/src/lib/repo/index.js +1315 -0
- package/studio/src/lib/repo/memory-adapter.js +115 -0
- package/studio/src/lib/repo/remote-adapter.js +158 -0
- package/studio/src/lib/repo/schema.js +143 -0
- package/studio/src/lib/repo/select-adapter.js +345 -0
- package/studio/src/lib/router.js +71 -0
- package/studio/src/lib/runner/browser.js +244 -0
- package/studio/src/lib/runner/checks.js +248 -0
- package/studio/src/lib/runner/current-code.js +98 -0
- package/studio/src/lib/runner/esm-cjs.js +109 -0
- package/studio/src/lib/runner/hash.js +34 -0
- package/studio/src/lib/runner/history.js +48 -0
- package/studio/src/lib/runner/index.js +168 -0
- package/studio/src/lib/runner/languages.js +258 -0
- package/studio/src/lib/runner/local.js +139 -0
- package/studio/src/lib/runner/path.js +104 -0
- package/studio/src/lib/runner/skeleton.js +315 -0
- package/studio/src/lib/runner/strip-types.js +134 -0
- package/studio/src/lib/settings.js +399 -0
- package/studio/src/lib/srs.js +39 -0
- package/templates/agent/settings.json +6 -0
- package/templates/claude/plugin.json +139 -0
- package/templates/claude/settings.json +15 -0
- package/templates/cursor/professor.mdc +4 -0
- package/templates/cursor/settings.json +18 -0
- package/templates/gemini/GEMINI.md +28 -0
- package/templates/gemini/settings.json +5 -0
- package/templates/opencode/opencode.json +3 -0
- package/templates/researcher/README.md +61 -0
- package/templates/researcher/settings.json +18 -0
- package/web/client/components.json +15 -0
- package/web/client/index.html +12 -0
- package/web/client/package-lock.json +8732 -0
- package/web/client/package.json +39 -0
- package/web/client/postcss.config.js +6 -0
- package/web/client/src/App.jsx +140 -0
- package/web/client/src/api/client.js +357 -0
- package/web/client/src/components/ChatPanel.jsx +417 -0
- package/web/client/src/components/CommandPills.jsx +50 -0
- package/web/client/src/components/DeprecationBanner.jsx +21 -0
- package/web/client/src/components/ExerciseEditor.jsx +164 -0
- package/web/client/src/components/Header.jsx +119 -0
- package/web/client/src/components/LecturePanel.jsx +342 -0
- package/web/client/src/components/MobileTabSwitcher.jsx +51 -0
- package/web/client/src/components/SplitPane.jsx +42 -0
- package/web/client/src/components/ui/alert.jsx +38 -0
- package/web/client/src/components/ui/badge.jsx +24 -0
- package/web/client/src/components/ui/button.jsx +23 -0
- package/web/client/src/components/ui/select.jsx +74 -0
- package/web/client/src/hooks/useSSE.js +152 -0
- package/web/client/src/hooks/useWebSocket.js +98 -0
- package/web/client/src/index.css +23 -0
- package/web/client/src/lib/utils.js +6 -0
- package/web/client/src/main.jsx +12 -0
- package/web/client/src/utils/markdown.js +50 -0
- package/web/client/tailwind.config.js +8 -0
- package/web/client/vite.config.js +21 -0
- package/web/dist/assets/index-C1W0eXIQ.js +294 -0
- package/web/dist/assets/index-C3OUx70T.css +1 -0
- package/web/dist/index.html +13 -0
- package/web/lecture-archive.js +172 -0
- package/web/legacy-server.js +1277 -0
- package/web/package-lock.json +855 -0
- package/web/package.json +10 -0
- package/web/security.js +1016 -0
- package/web/server.js +390 -0
- package/web/studio-api/agents.js +580 -0
- package/web/studio-api/bridge.js +199 -0
- package/web/studio-api/db.js +66 -0
- package/web/studio-api/guards.js +201 -0
- package/web/studio-api/health.js +538 -0
- package/web/studio-api.js +214 -0
- package/web/studio-db.js +380 -0
- package/web/studio-runner.js +568 -0
package/web/server.js
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* web/server.js — side-effect-free application factory plus the process entry point.
|
|
3
|
+
*
|
|
4
|
+
* Importing this module binds no port, creates no directory, spawns nothing and logs nothing.
|
|
5
|
+
* `createApp({ legacy })` builds the Express app; `startServer()` resolves the token, derives the
|
|
6
|
+
* configuration and calls `listen`. Studio-only is the default; legacy mode is the single explicit
|
|
7
|
+
* opt-in and requires `web/legacy-server.js` (Plan 03).
|
|
8
|
+
*/
|
|
9
|
+
import express from 'express';
|
|
10
|
+
import { createServer } from 'http';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
import { join, dirname, resolve } from 'path';
|
|
13
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
14
|
+
import { createStudioRouter } from './studio-api.js';
|
|
15
|
+
import { buildOriginSet } from './studio-api/guards.js';
|
|
16
|
+
import { createStaticHandler } from '../bin/static-server.js';
|
|
17
|
+
import * as security from './security.js';
|
|
18
|
+
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const REPO_ROOT = join(__dirname, '..');
|
|
21
|
+
|
|
22
|
+
const STUDIO_BUILD_MESSAGE = `<!doctype html>
|
|
23
|
+
<html><head><meta charset="utf-8"><title>Professor Studio</title></head>
|
|
24
|
+
<body>
|
|
25
|
+
<h1>Professor Studio build not found</h1>
|
|
26
|
+
<p>Run <code>skillforce studio</code> or build Studio with <code>npm run build:studio</code>.</p>
|
|
27
|
+
</body></html>`;
|
|
28
|
+
|
|
29
|
+
const LEGACY_BUILD_MESSAGE = `<!doctype html>
|
|
30
|
+
<html><head><meta charset="utf-8"><title>Professor Web UI</title></head>
|
|
31
|
+
<body>
|
|
32
|
+
<h1>Legacy web build not found</h1>
|
|
33
|
+
<p>Run <code>npm run build</code> from the repository root, or use Professor Studio.</p>
|
|
34
|
+
</body></html>`;
|
|
35
|
+
|
|
36
|
+
function defaultCoursesDir() {
|
|
37
|
+
return process.env.COURSES_DIR || './courses';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function defaultStudioDist() {
|
|
41
|
+
return process.env.STUDIO_DIST || join(REPO_ROOT, 'studio', 'dist');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* ------------------------------------------------------------------ UI mounting */
|
|
45
|
+
|
|
46
|
+
function mountStaticUi(app, { root, buildMessage, log }) {
|
|
47
|
+
const indexPath = join(root, 'index.html');
|
|
48
|
+
const handler = createStaticHandler({ root, spaFallback: true, log });
|
|
49
|
+
|
|
50
|
+
app.use((req, res, next) => {
|
|
51
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
52
|
+
next();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!existsSync(indexPath)) {
|
|
56
|
+
res.status(503).type('html').send(buildMessage);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
handler(req, res, next);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* ------------------------------------------------------------------ app factory */
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Build the Express application. Never binds a port, resolves a token, spawns a process or creates
|
|
67
|
+
* a directory; tests inject a temp DB, courses dir and Studio dist.
|
|
68
|
+
*
|
|
69
|
+
* Exactly one UI is served at `/` (D-24):
|
|
70
|
+
* - Studio-only: `studio/dist` (503 build message when missing)
|
|
71
|
+
* - legacy production: `legacyDist` (default `web/client/dist`)
|
|
72
|
+
* - legacy dev: no UI on this port (Vite on 5173 owns it)
|
|
73
|
+
*
|
|
74
|
+
* @param {object} [options]
|
|
75
|
+
* @param {boolean} [options.legacy] serve the legacy API/UI (requires web/legacy-server.js)
|
|
76
|
+
* @param {string} [options.nodeEnv]
|
|
77
|
+
* @param {string} [options.token] static pairing token
|
|
78
|
+
* @param {() => string} [options.getToken] pairing-token getter
|
|
79
|
+
* @param {Set<string>|string} [options.origins]
|
|
80
|
+
* @param {object} [options.db]
|
|
81
|
+
* @param {string} [options.coursesDir]
|
|
82
|
+
* @param {string} [options.studioDist]
|
|
83
|
+
* @param {string} [options.legacyDist]
|
|
84
|
+
* @param {(...a:any[])=>void} [options.log]
|
|
85
|
+
* @param {Record<string, Function>} [options.runners]
|
|
86
|
+
* @param {Record<string, Function>} [options.legacyRunners] legacy chat agent runners
|
|
87
|
+
* @param {() => object} [options.capabilities]
|
|
88
|
+
* @param {object} [options.capabilityCache] legacy capability TTL cache (tests)
|
|
89
|
+
* @param {boolean} [options.useCli] result of the one-time Claude CLI probe
|
|
90
|
+
* @param {Function} [options.spawnImpl]
|
|
91
|
+
* @param {boolean} [options.allowNonLoopback]
|
|
92
|
+
* @param {string[]} [options.extraHosts]
|
|
93
|
+
* @returns {Promise<import('express').Express>}
|
|
94
|
+
*/
|
|
95
|
+
export async function createApp({
|
|
96
|
+
legacy = false,
|
|
97
|
+
nodeEnv = process.env.NODE_ENV || 'development',
|
|
98
|
+
token,
|
|
99
|
+
getToken,
|
|
100
|
+
origins,
|
|
101
|
+
db,
|
|
102
|
+
coursesDir = defaultCoursesDir(),
|
|
103
|
+
studioDist = defaultStudioDist(),
|
|
104
|
+
legacyDist = join(__dirname, 'client', 'dist'),
|
|
105
|
+
log = console.log,
|
|
106
|
+
runners,
|
|
107
|
+
legacyRunners,
|
|
108
|
+
capabilities,
|
|
109
|
+
capabilityCache,
|
|
110
|
+
useCli = false,
|
|
111
|
+
spawnImpl,
|
|
112
|
+
allowNonLoopback = false,
|
|
113
|
+
extraHosts,
|
|
114
|
+
} = {}) {
|
|
115
|
+
const resolvedExtraHosts =
|
|
116
|
+
extraHosts ?? security.resolveExtraHosts({ env: process.env, host: process.env.HOST });
|
|
117
|
+
|
|
118
|
+
const app = express();
|
|
119
|
+
|
|
120
|
+
// Global Host guard (covers static assets too). Token/Origin/JSON stay on the API routers.
|
|
121
|
+
app.use((req, res, next) => {
|
|
122
|
+
if (!security.isAllowedHost(req.headers?.host, { extraHosts: resolvedExtraHosts })) {
|
|
123
|
+
res.status(403).json({ ok: false, error: 'Forbidden host', code: 'forbidden_host' });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (!allowNonLoopback && !security.isLoopbackAddress(req.socket?.remoteAddress)) {
|
|
127
|
+
res.status(403).json({
|
|
128
|
+
ok: false,
|
|
129
|
+
error: 'Studio bridge accepts loopback clients only',
|
|
130
|
+
code: 'forbidden_client',
|
|
131
|
+
});
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
next();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
app.use(
|
|
138
|
+
'/api/studio',
|
|
139
|
+
createStudioRouter({
|
|
140
|
+
token,
|
|
141
|
+
getToken,
|
|
142
|
+
origins,
|
|
143
|
+
allowNonLoopback,
|
|
144
|
+
extraHosts: resolvedExtraHosts,
|
|
145
|
+
db,
|
|
146
|
+
runners,
|
|
147
|
+
capabilities,
|
|
148
|
+
log,
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
if (legacy) {
|
|
153
|
+
let legacyModule;
|
|
154
|
+
try {
|
|
155
|
+
legacyModule = await import('./legacy-server.js');
|
|
156
|
+
} catch (cause) {
|
|
157
|
+
const err = new Error(
|
|
158
|
+
'Legacy mode requires web/legacy-server.js. ' +
|
|
159
|
+
'Install the full package or run without --legacy.'
|
|
160
|
+
);
|
|
161
|
+
err.code = 'legacy_unavailable';
|
|
162
|
+
err.cause = cause;
|
|
163
|
+
throw err;
|
|
164
|
+
}
|
|
165
|
+
if (typeof legacyModule.createLegacyRouter !== 'function') {
|
|
166
|
+
const err = new Error('web/legacy-server.js does not export createLegacyRouter.');
|
|
167
|
+
err.code = 'legacy_unavailable';
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
170
|
+
const legacyGetToken =
|
|
171
|
+
typeof getToken === 'function'
|
|
172
|
+
? getToken
|
|
173
|
+
: typeof token === 'string'
|
|
174
|
+
? () => token
|
|
175
|
+
: undefined;
|
|
176
|
+
|
|
177
|
+
app.use(
|
|
178
|
+
legacyModule.createLegacyRouter({
|
|
179
|
+
coursesDir,
|
|
180
|
+
token,
|
|
181
|
+
getToken: legacyGetToken,
|
|
182
|
+
origins,
|
|
183
|
+
allowNonLoopback,
|
|
184
|
+
extraHosts: resolvedExtraHosts,
|
|
185
|
+
spawnImpl,
|
|
186
|
+
capabilities,
|
|
187
|
+
capabilityCache,
|
|
188
|
+
useCli,
|
|
189
|
+
runners: legacyRunners,
|
|
190
|
+
log,
|
|
191
|
+
})
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// API 404 before any UI fallback so `/api/*` can never return HTML.
|
|
196
|
+
app.use('/api', (req, res) => {
|
|
197
|
+
res.status(404).json({ ok: false, error: 'Not found', code: 'not_found' });
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
if (!legacy) {
|
|
201
|
+
mountStaticUi(app, { root: studioDist, buildMessage: STUDIO_BUILD_MESSAGE, log });
|
|
202
|
+
} else if (nodeEnv === 'production') {
|
|
203
|
+
mountStaticUi(app, { root: legacyDist, buildMessage: LEGACY_BUILD_MESSAGE, log });
|
|
204
|
+
} else {
|
|
205
|
+
// Legacy dev: Vite owns the UI on 5173. Never serve Studio's index on this port.
|
|
206
|
+
app.get('/', (req, res) => {
|
|
207
|
+
res
|
|
208
|
+
.status(200)
|
|
209
|
+
.type('html')
|
|
210
|
+
.send(
|
|
211
|
+
'<!doctype html><html><body><h1>Legacy UI runs on Vite</h1>' +
|
|
212
|
+
'<p>Open <a href="http://localhost:5173">http://localhost:5173</a>.</p></body></html>'
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return app;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* ------------------------------------------------------------------ entry point */
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Resolve configuration, build the app and bind the server.
|
|
224
|
+
*
|
|
225
|
+
* @param {object} [options]
|
|
226
|
+
* @param {number|string} [options.port]
|
|
227
|
+
* @param {string} [options.host]
|
|
228
|
+
* @param {boolean} [options.legacy]
|
|
229
|
+
* @param {Record<string,string|undefined>} [options.env]
|
|
230
|
+
* @param {string[]} [options.argv]
|
|
231
|
+
* @param {boolean} [options.logBanner]
|
|
232
|
+
* @returns {Promise<{ app: import('express').Express, server: import('http').Server,
|
|
233
|
+
* token: string, origins: Set<string>, uiUrl: string,
|
|
234
|
+
* close: () => Promise<void> }>}
|
|
235
|
+
*/
|
|
236
|
+
export async function startServer({
|
|
237
|
+
port,
|
|
238
|
+
host,
|
|
239
|
+
legacy,
|
|
240
|
+
env = process.env,
|
|
241
|
+
argv = process.argv,
|
|
242
|
+
logBanner,
|
|
243
|
+
spawnImpl,
|
|
244
|
+
platform,
|
|
245
|
+
...appOptions
|
|
246
|
+
} = {}) {
|
|
247
|
+
const legacyEnabled =
|
|
248
|
+
legacy === true || env.PROFESSOR_LEGACY === '1' || argv.includes('--legacy');
|
|
249
|
+
const nodeEnv = appOptions.nodeEnv ?? env.NODE_ENV ?? 'development';
|
|
250
|
+
const resolvedPort = port ?? env.PORT ?? 3000;
|
|
251
|
+
const resolvedHost = host ?? env.HOST ?? '127.0.0.1';
|
|
252
|
+
|
|
253
|
+
if (['0.0.0.0', '::', '*', '[::]'].includes(String(resolvedHost))) {
|
|
254
|
+
const err = new Error(`Refusing to bind a wildcard host: ${resolvedHost}`);
|
|
255
|
+
err.code = 'insecure_config';
|
|
256
|
+
throw err;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const extraHosts = security.resolveExtraHosts({ env, host: resolvedHost });
|
|
260
|
+
const optIn = security.isNonLoopbackOptIn(env);
|
|
261
|
+
const legacyFile = security.legacyTokenPath(REPO_ROOT);
|
|
262
|
+
|
|
263
|
+
const { token: explicitToken, getToken: explicitGetter, origins: explicitOrigins, ...rest } =
|
|
264
|
+
appOptions;
|
|
265
|
+
|
|
266
|
+
const token = explicitToken ?? security.ensureStudioToken({ env, legacyFile });
|
|
267
|
+
const getToken = explicitGetter ?? security.createTokenGetter({ env, legacyFile });
|
|
268
|
+
const origins =
|
|
269
|
+
explicitOrigins ??
|
|
270
|
+
buildOriginSet({
|
|
271
|
+
envValue: env.STUDIO_ORIGINS,
|
|
272
|
+
ownPort: resolvedPort,
|
|
273
|
+
legacyDev: legacyEnabled && nodeEnv !== 'production',
|
|
274
|
+
studioPort: env.STUDIO_STATIC_PORT,
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
if (security.isWildcardOrigins(origins) && optIn) {
|
|
278
|
+
const err = new Error(
|
|
279
|
+
'STUDIO_ORIGINS=* cannot be combined with STUDIO_ALLOW_NON_LOOPBACK; refusing to start.'
|
|
280
|
+
);
|
|
281
|
+
err.code = 'insecure_config';
|
|
282
|
+
throw err;
|
|
283
|
+
}
|
|
284
|
+
if (optIn) {
|
|
285
|
+
console.error(
|
|
286
|
+
'[security] STUDIO_ALLOW_NON_LOOPBACK is enabled: non-loopback clients/hosts are allowed. ' +
|
|
287
|
+
'Only do this on a trusted network.'
|
|
288
|
+
);
|
|
289
|
+
} else if (security.isWildcardOrigins(origins)) {
|
|
290
|
+
console.error(
|
|
291
|
+
'[security] STUDIO_ORIGINS=* is enabled: any non-null Origin is echoed (never `*`). ' +
|
|
292
|
+
'Only do this while paired on a trusted machine.'
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
let legacyModule = null;
|
|
297
|
+
let useCli = appOptions.useCli;
|
|
298
|
+
if (legacyEnabled) {
|
|
299
|
+
console.error(
|
|
300
|
+
'[deprecated] Legacy web UI is enabled. Use Professor Studio at http://localhost:5180.'
|
|
301
|
+
);
|
|
302
|
+
legacyModule = await import('./legacy-server.js');
|
|
303
|
+
if (useCli === undefined) useCli = legacyModule.claudeCLIAvailable({ platform });
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const app = await createApp({
|
|
307
|
+
...rest,
|
|
308
|
+
legacy: legacyEnabled,
|
|
309
|
+
nodeEnv,
|
|
310
|
+
token,
|
|
311
|
+
getToken,
|
|
312
|
+
origins,
|
|
313
|
+
coursesDir: rest.coursesDir ?? env.COURSES_DIR ?? './courses',
|
|
314
|
+
studioDist: rest.studioDist ?? env.STUDIO_DIST ?? join(REPO_ROOT, 'studio', 'dist'),
|
|
315
|
+
legacyDist:
|
|
316
|
+
rest.legacyDist ?? env.LEGACY_DIST ?? join(REPO_ROOT, 'web', 'client', 'dist'),
|
|
317
|
+
useCli,
|
|
318
|
+
spawnImpl,
|
|
319
|
+
extraHosts,
|
|
320
|
+
allowNonLoopback: rest.allowNonLoopback ?? (optIn || extraHosts.length > 0),
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const server = createServer(app);
|
|
324
|
+
await new Promise((resolveListen, reject) => {
|
|
325
|
+
server.once('error', reject);
|
|
326
|
+
server.listen(resolvedPort, resolvedHost, () => {
|
|
327
|
+
server.removeListener('error', reject);
|
|
328
|
+
resolveListen();
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const uiUrl =
|
|
333
|
+
legacyEnabled && nodeEnv !== 'production'
|
|
334
|
+
? 'http://localhost:5173'
|
|
335
|
+
: `http://localhost:${resolvedPort}`;
|
|
336
|
+
|
|
337
|
+
let legacyDev = null;
|
|
338
|
+
if (legacyEnabled && nodeEnv !== 'production') {
|
|
339
|
+
legacyDev = legacyModule.startLegacyDevServer({
|
|
340
|
+
clientDir: join(REPO_ROOT, 'web', 'client'),
|
|
341
|
+
spawnImpl,
|
|
342
|
+
platform,
|
|
343
|
+
log: appOptions.log ?? console.log,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
let pairingUrl = `${uiUrl}/#token=${encodeURIComponent(token)}`;
|
|
348
|
+
if (Number(resolvedPort) !== 3000) {
|
|
349
|
+
pairingUrl += `&bridge=${encodeURIComponent(`http://localhost:${resolvedPort}`)}`;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (logBanner !== false) {
|
|
353
|
+
const output = [
|
|
354
|
+
'',
|
|
355
|
+
'┌─ Professor Studio ───────────────────────────────────────────',
|
|
356
|
+
`│ UI: ${uiUrl}`,
|
|
357
|
+
`│ Pairing token: ${security.maskToken(token)}`,
|
|
358
|
+
`│ Pairing URL: ${pairingUrl}`,
|
|
359
|
+
`│ Allowed origins: ${[...origins].join(', ')}`,
|
|
360
|
+
'└──────────────────────────────────────────────────────────────',
|
|
361
|
+
'',
|
|
362
|
+
].join('\n');
|
|
363
|
+
(appOptions.log ?? console.log)(output);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const close = () =>
|
|
367
|
+
new Promise((resolveClose) => {
|
|
368
|
+
legacyDev?.kill?.();
|
|
369
|
+
if (!server.listening) {
|
|
370
|
+
resolveClose();
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
server.close(() => resolveClose());
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
return { app, server, token, origins, uiUrl, close };
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/* ------------------------------------------------------------------ process entry */
|
|
380
|
+
|
|
381
|
+
const entryPath = process.argv[1];
|
|
382
|
+
const isEntryPoint =
|
|
383
|
+
Boolean(entryPath) && pathToFileURL(resolve(entryPath)).href === import.meta.url;
|
|
384
|
+
|
|
385
|
+
if (isEntryPoint) {
|
|
386
|
+
startServer().catch((err) => {
|
|
387
|
+
console.error(`Error: ${err.message}`);
|
|
388
|
+
process.exit(1);
|
|
389
|
+
});
|
|
390
|
+
}
|