keating 0.3.6

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 (249) hide show
  1. package/README.md +334 -0
  2. package/SYSTEM.md +33 -0
  3. package/bin/keating.js +31 -0
  4. package/dist/src/cli/main.js +357 -0
  5. package/dist/src/cli/setup.js +197 -0
  6. package/dist/src/cli/web.js +84 -0
  7. package/dist/src/core/animation.js +304 -0
  8. package/dist/src/core/ax-optimizer.js +81 -0
  9. package/dist/src/core/ax-prompt-learner.js +59 -0
  10. package/dist/src/core/ax-trial.js +181 -0
  11. package/dist/src/core/benchmark.js +253 -0
  12. package/dist/src/core/commands.js +57 -0
  13. package/dist/src/core/config.js +120 -0
  14. package/dist/src/core/engagement.js +235 -0
  15. package/dist/src/core/env.js +9 -0
  16. package/dist/src/core/evolution.js +242 -0
  17. package/dist/src/core/flashcards.js +133 -0
  18. package/dist/src/core/learner-state.js +108 -0
  19. package/dist/src/core/lesson-plan.js +155 -0
  20. package/dist/src/core/map-elites.js +228 -0
  21. package/dist/src/core/map.js +89 -0
  22. package/dist/src/core/mastery.js +207 -0
  23. package/dist/src/core/paths.js +100 -0
  24. package/dist/src/core/pi-agent.js +82 -0
  25. package/dist/src/core/policy.js +79 -0
  26. package/dist/src/core/project.js +337 -0
  27. package/dist/src/core/projects.js +281 -0
  28. package/dist/src/core/prompt-evolution.js +344 -0
  29. package/dist/src/core/quiz.js +194 -0
  30. package/dist/src/core/random.js +19 -0
  31. package/dist/src/core/self-improve.js +425 -0
  32. package/dist/src/core/speech.js +54 -0
  33. package/dist/src/core/terminal.js +117 -0
  34. package/dist/src/core/theme.js +101 -0
  35. package/dist/src/core/topics.js +620 -0
  36. package/dist/src/core/types.js +1 -0
  37. package/dist/src/core/util.js +30 -0
  38. package/dist/src/core/verification.js +162 -0
  39. package/dist/src/pi/hyperteacher-extension.js +573 -0
  40. package/dist/src/runtime/pi.js +343 -0
  41. package/package.json +78 -0
  42. package/pi/prompts/bridge.md +14 -0
  43. package/pi/prompts/diagnose.md +15 -0
  44. package/pi/prompts/improve.md +39 -0
  45. package/pi/prompts/learn.md +21 -0
  46. package/pi/prompts/quiz.md +14 -0
  47. package/pi/skills/adaptive-teaching/SKILL.md +33 -0
  48. package/scripts/install/install.sh +308 -0
  49. package/web/dist/.well-known/llms.txt +44 -0
  50. package/web/dist/apple-touch-icon.svg +10 -0
  51. package/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  52. package/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  53. package/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  54. package/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  55. package/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  56. package/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  57. package/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  58. package/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  59. package/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  60. package/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  61. package/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  62. package/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  63. package/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  64. package/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  65. package/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  66. package/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  67. package/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  68. package/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  69. package/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  70. package/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  71. package/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  72. package/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  73. package/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  74. package/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  75. package/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  76. package/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  77. package/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  78. package/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  79. package/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  80. package/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  81. package/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  82. package/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  83. package/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  84. package/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  85. package/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  86. package/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  87. package/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  88. package/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  89. package/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  90. package/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  91. package/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  92. package/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  93. package/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  94. package/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  95. package/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  96. package/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  97. package/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  98. package/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  99. package/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  100. package/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  101. package/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  102. package/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  103. package/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  104. package/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  105. package/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  106. package/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  107. package/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  108. package/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  109. package/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  110. package/web/dist/assets/_baseFor-B_cjfMB6.js +1 -0
  111. package/web/dist/assets/anthropic-BT6Vfzb1.js +36 -0
  112. package/web/dist/assets/arc-x2nTilpc.js +1 -0
  113. package/web/dist/assets/architecture-YZFGNWBL-B1hlUWjX.js +1 -0
  114. package/web/dist/assets/architectureDiagram-Q4EWVU46-CMApWFyw.js +36 -0
  115. package/web/dist/assets/array-B9UHiPd-.js +1 -0
  116. package/web/dist/assets/azure-openai-responses-CommX3YJ.js +1 -0
  117. package/web/dist/assets/blockDiagram-DXYQGD6D-DOQbsNRY.js +132 -0
  118. package/web/dist/assets/c4Diagram-AHTNJAMY-VFfRZWWA.js +10 -0
  119. package/web/dist/assets/channel-KY2Tg8Ba.js +1 -0
  120. package/web/dist/assets/chunk-2KRD3SAO-B-AqvS0u.js +1 -0
  121. package/web/dist/assets/chunk-336JU56O-DlYgPyl6.js +2 -0
  122. package/web/dist/assets/chunk-426QAEUC-CsVoBkfR.js +1 -0
  123. package/web/dist/assets/chunk-4BX2VUAB-0Z13aFAn.js +1 -0
  124. package/web/dist/assets/chunk-4TB4RGXK-DqC0Zwm7.js +206 -0
  125. package/web/dist/assets/chunk-55IACEB6-CWE_u-IY.js +1 -0
  126. package/web/dist/assets/chunk-5FUZZQ4R-CApli0xX.js +62 -0
  127. package/web/dist/assets/chunk-5PVQY5BW-Cbzhfhln.js +2 -0
  128. package/web/dist/assets/chunk-67CJDMHE-Cx7uJS4d.js +1 -0
  129. package/web/dist/assets/chunk-7N4EOEYR-CYPNsFus.js +1 -0
  130. package/web/dist/assets/chunk-AA7GKIK3-rU0uhR_u.js +1 -0
  131. package/web/dist/assets/chunk-BSJP7CBP-5VmcfR4-.js +1 -0
  132. package/web/dist/assets/chunk-Bj-mKKzh.js +1 -0
  133. package/web/dist/assets/chunk-CIAEETIT-CHJ-L8H1.js +1 -0
  134. package/web/dist/assets/chunk-EDXVE4YY-DZHAJjMI.js +1 -0
  135. package/web/dist/assets/chunk-ENJZ2VHE-DbUDFa7w.js +10 -0
  136. package/web/dist/assets/chunk-FMBD7UC4-BsYE5e_h.js +15 -0
  137. package/web/dist/assets/chunk-FOC6F5B3-Cm6aoTv7.js +1 -0
  138. package/web/dist/assets/chunk-ICPOFSXX-C5eNZ4L6.js +123 -0
  139. package/web/dist/assets/chunk-K5T4RW27-R7dAJ4rq.js +94 -0
  140. package/web/dist/assets/chunk-KGLVRYIC-MO99YZXL.js +1 -0
  141. package/web/dist/assets/chunk-LIHQZDEY-DUJ656sT.js +1 -0
  142. package/web/dist/assets/chunk-ORNJ4GCN-DXuuEC1n.js +1 -0
  143. package/web/dist/assets/chunk-OYMX7WX6-pJlEprWq.js +231 -0
  144. package/web/dist/assets/chunk-QZHKN3VN-_pQxbbiW.js +1 -0
  145. package/web/dist/assets/chunk-U2HBQHQK-Mh_l9PLe.js +70 -0
  146. package/web/dist/assets/chunk-X2U36JSP-BOeiJW0w.js +1 -0
  147. package/web/dist/assets/chunk-XPW4576I-fQ9SDvr_.js +32 -0
  148. package/web/dist/assets/chunk-YZCP3GAM-eboO4P5S.js +1 -0
  149. package/web/dist/assets/chunk-ZZ45TVLE-Cky0eqlr.js +1 -0
  150. package/web/dist/assets/classDiagram-6PBFFD2Q-DEPsZSU3.js +1 -0
  151. package/web/dist/assets/classDiagram-v2-HSJHXN6E-DhmIOEpX.js +1 -0
  152. package/web/dist/assets/clone-DeTzYqo8.js +1 -0
  153. package/web/dist/assets/cose-bilkent-S5V4N54A-N4zWUJ7C.js +1 -0
  154. package/web/dist/assets/cytoscape.esm-BBMd0vGm.js +321 -0
  155. package/web/dist/assets/dagre-IpK1aoMm.js +1 -0
  156. package/web/dist/assets/dagre-KV5264BT-DCytJuju.js +4 -0
  157. package/web/dist/assets/defaultLocale-5eAKkKJC.js +1 -0
  158. package/web/dist/assets/diagram-5BDNPKRD-Cv4miBae.js +10 -0
  159. package/web/dist/assets/diagram-G4DWMVQ6-CtICKUFi.js +24 -0
  160. package/web/dist/assets/diagram-MMDJMWI5-Cn7aGorh.js +43 -0
  161. package/web/dist/assets/diagram-TYMM5635-CCUWDPsC.js +24 -0
  162. package/web/dist/assets/dist-Dm98VvTW.js +1 -0
  163. package/web/dist/assets/env-api-keys-BNlMKqxw.js +1 -0
  164. package/web/dist/assets/erDiagram-SMLLAGMA-uT88sBlT.js +85 -0
  165. package/web/dist/assets/event-stream-D33K9rpL.js +1 -0
  166. package/web/dist/assets/flatten-C-u5nd5-.js +1 -0
  167. package/web/dist/assets/flowDiagram-DWJPFMVM-Bl3O7S1m.js +162 -0
  168. package/web/dist/assets/ganttDiagram-T4ZO3ILL-B1FhwV45.js +292 -0
  169. package/web/dist/assets/gitGraph-7Q5UKJZL-Bc_7vzer.js +1 -0
  170. package/web/dist/assets/gitGraphDiagram-UUTBAWPF-DfW6svMS.js +106 -0
  171. package/web/dist/assets/github-copilot-headers-L39QqneT.js +1 -0
  172. package/web/dist/assets/google-BdYNeCP_.js +1 -0
  173. package/web/dist/assets/google-gemini-cli-DpxAL3K4.js +2 -0
  174. package/web/dist/assets/google-shared-DyQdgtsI.js +2 -0
  175. package/web/dist/assets/google-vertex-CKRybaXj.js +1 -0
  176. package/web/dist/assets/graphlib-CMTVFyOZ.js +1 -0
  177. package/web/dist/assets/hash-kZ2KD_no.js +1 -0
  178. package/web/dist/assets/index-Bdb7P7gx.css +2 -0
  179. package/web/dist/assets/index-DNxepp8B.js +2891 -0
  180. package/web/dist/assets/info-OMHHGYJF-BGcxeaZt.js +1 -0
  181. package/web/dist/assets/infoDiagram-42DDH7IO-BbES7X_c.js +2 -0
  182. package/web/dist/assets/init-DlZdxViB.js +1 -0
  183. package/web/dist/assets/isEmpty-DssUW35f.js +1 -0
  184. package/web/dist/assets/ishikawaDiagram-UXIWVN3A-DxQ28rho.js +70 -0
  185. package/web/dist/assets/journeyDiagram-VCZTEJTY-D0X8qQ0P.js +139 -0
  186. package/web/dist/assets/json-parse-C6tSeIxX.js +2 -0
  187. package/web/dist/assets/kanban-definition-6JOO6SKY-DWYfSlpl.js +89 -0
  188. package/web/dist/assets/katex-CyM-5LlM.js +265 -0
  189. package/web/dist/assets/line-CuHce5JG.js +1 -0
  190. package/web/dist/assets/linear-Ca0Vkwuj.js +1 -0
  191. package/web/dist/assets/mermaid-parser.core-Cy4iY_Dy.js +4 -0
  192. package/web/dist/assets/mermaid.core-6PGkQdYc.js +11 -0
  193. package/web/dist/assets/mindmap-definition-QFDTVHPH-BBnKdtQh.js +96 -0
  194. package/web/dist/assets/mistral-BWaUMIgd.js +7 -0
  195. package/web/dist/assets/openai-D4NSaQIs.js +16 -0
  196. package/web/dist/assets/openai-codex-responses-CHBgKhmb.js +7 -0
  197. package/web/dist/assets/openai-completions-kcXmmaHI.js +5 -0
  198. package/web/dist/assets/openai-responses-Cqq3H3p3.js +1 -0
  199. package/web/dist/assets/openai-responses-shared-CTNuo9ci.js +10 -0
  200. package/web/dist/assets/ordinal-_K3x1fkz.js +1 -0
  201. package/web/dist/assets/ort-wasm-simd-threaded.jsep-B0T3yYHD.wasm +0 -0
  202. package/web/dist/assets/packet-4T2RLAQJ-D35ZLSBH.js +1 -0
  203. package/web/dist/assets/path-6uRLdFF7.js +1 -0
  204. package/web/dist/assets/pdf.worker.min-Cpi8b8z3.mjs +28 -0
  205. package/web/dist/assets/pie-ZZUOXDRM-DRoETpJX.js +1 -0
  206. package/web/dist/assets/pieDiagram-DEJITSTG-DfMjfTQz.js +30 -0
  207. package/web/dist/assets/preload-helper-DSXbuxSR.js +1 -0
  208. package/web/dist/assets/quadrantDiagram-34T5L4WZ-DfBSEept.js +7 -0
  209. package/web/dist/assets/radar-PYXPWWZC-DLKxRJ0V.js +1 -0
  210. package/web/dist/assets/reduce-836A2NiQ.js +1 -0
  211. package/web/dist/assets/requirementDiagram-MS252O5E-BPkxJQkz.js +84 -0
  212. package/web/dist/assets/rough.esm-Djo4Abte.js +1 -0
  213. package/web/dist/assets/sankeyDiagram-XADWPNL6-He3x9tNT.js +10 -0
  214. package/web/dist/assets/sequenceDiagram-FGHM5R23-DfCDpvrT.js +157 -0
  215. package/web/dist/assets/src-DdOdIreR.js +1 -0
  216. package/web/dist/assets/stateDiagram-FHFEXIEX-fuww6347.js +1 -0
  217. package/web/dist/assets/stateDiagram-v2-QKLJ7IA2-U6voafO3.js +1 -0
  218. package/web/dist/assets/timeline-definition-GMOUNBTQ-BWunHgBC.js +120 -0
  219. package/web/dist/assets/transform-messages-CqKEdRVp.js +1 -0
  220. package/web/dist/assets/transformers.web-DKUtmSAi.js +2818 -0
  221. package/web/dist/assets/treeView-SZITEDCU-BCx0xSAm.js +1 -0
  222. package/web/dist/assets/treemap-W4RFUUIX-2CvghWJK.js +1 -0
  223. package/web/dist/assets/vennDiagram-DHZGUBPP-CBXRutSP.js +34 -0
  224. package/web/dist/assets/wardley-RL74JXVD-BkPL_mhd.js +1 -0
  225. package/web/dist/assets/wardleyDiagram-NUSXRM2D-DTcVscPH.js +20 -0
  226. package/web/dist/assets/web-CMKYLKbT.js +10 -0
  227. package/web/dist/assets/xychartDiagram-5P7HB3ND-CZLgX9Fe.js +7 -0
  228. package/web/dist/favicon.svg +10 -0
  229. package/web/dist/index.html +104 -0
  230. package/web/dist/keating-metaharness.pdf +10557 -3
  231. package/web/dist/llms.txt +44 -0
  232. package/web/dist/logo.png +0 -0
  233. package/web/dist/manifest.webmanifest +1 -0
  234. package/web/dist/og-image.png +0 -0
  235. package/web/dist/pwa-192x192.svg +10 -0
  236. package/web/dist/pwa-512x512.svg +10 -0
  237. package/web/dist/registerSW.js +1 -0
  238. package/web/dist/robots.txt +8 -0
  239. package/web/dist/sitemap.xml +39 -0
  240. package/web/dist/sw.js +1 -0
  241. package/web/dist/tapes/doctor.mp4 +0 -0
  242. package/web/dist/tapes/feedback-flow.mp4 +0 -0
  243. package/web/dist/tapes/improve-flow.mp4 +0 -0
  244. package/web/dist/tapes/intro.mp4 +0 -0
  245. package/web/dist/tapes/learning-flow.mp4 +0 -0
  246. package/web/dist/tapes/session-flow.mp4 +0 -0
  247. package/web/dist/tapes/teacher-flow.mp4 +0 -0
  248. package/web/dist/tapes/tests.mp4 +0 -0
  249. package/web/dist/workbox-66610c77.js +1 -0
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Projects & Assignments Engine — long-horizon learning with milestones.
3
+ *
4
+ * Learners get multi-stage projects that span days or weeks, with:
5
+ * - Milestones (verified checkpoints)
6
+ * - Deliverables (artifacts to produce)
7
+ * - Rubrics (grading criteria)
8
+ * - Progress tracking
9
+ */
10
+ import { resolveTopic } from "./topics.js";
11
+ // ─── Project Generation ───────────────────────────────────────────────────
12
+ export function generateProject(topicName) {
13
+ const topic = resolveTopic(topicName);
14
+ const id = `proj-${topic.slug}-${Date.now().toString(36)}`;
15
+ const milestones = [
16
+ {
17
+ id: `${id}-m1`,
18
+ title: "Research & Foundation",
19
+ description: `Investigate the core definitions, history, and key figures behind ${topic.title}.`,
20
+ deliverables: [
21
+ {
22
+ id: `${id}-d1`,
23
+ title: "Concept Map",
24
+ description: `Create a concept map showing ${topic.title}, its prerequisites, and key relationships.`,
25
+ format: "diagram",
26
+ rubric: [
27
+ "Includes core concept node",
28
+ "Links to at least 3 prerequisites",
29
+ "Shows relationship arrows with labels",
30
+ "Identifies at least 1 common misconception"
31
+ ]
32
+ },
33
+ {
34
+ id: `${id}-d2`,
35
+ title: "Annotated Summary",
36
+ description: `Write a 200-word summary of ${topic.title} annotated with your own questions and connections.`,
37
+ format: "essay",
38
+ minWords: 200,
39
+ rubric: [
40
+ "Accurately captures core definition",
41
+ "Includes at least 2 personal questions",
42
+ "Connects to prior knowledge",
43
+ "Identifies what is still unclear"
44
+ ]
45
+ }
46
+ ],
47
+ estimatedHours: 2,
48
+ prerequisites: topic.prerequisites,
49
+ status: "not_started"
50
+ },
51
+ {
52
+ id: `${id}-m2`,
53
+ title: "Deep Dive",
54
+ description: `Work through examples and exercises demonstrating ${topic.title} in practice.`,
55
+ deliverables: [
56
+ {
57
+ id: `${id}-d3`,
58
+ title: "Worked Examples",
59
+ description: `Solve ${topic.examples.length} worked examples, showing all reasoning.`,
60
+ format: "implementation",
61
+ rubric: [
62
+ "All steps shown with justification",
63
+ "At least one alternative approach explored",
64
+ "Common mistakes identified and avoided",
65
+ "Final answer verifiable"
66
+ ]
67
+ },
68
+ {
69
+ id: `${id}-d4`,
70
+ title: "Practice Problems",
71
+ description: `Create 3 original practice problems on ${topic.title} with solutions.`,
72
+ format: "implementation",
73
+ rubric: [
74
+ "Problems cover different difficulty levels",
75
+ "Solutions are correct and complete",
76
+ "At least one problem targets a known misconception",
77
+ "Clear marking scheme provided"
78
+ ]
79
+ }
80
+ ],
81
+ estimatedHours: 4,
82
+ prerequisites: [],
83
+ status: "not_started"
84
+ },
85
+ {
86
+ id: `${id}-m3`,
87
+ title: "Transfer & Synthesis",
88
+ description: `Apply ${topic.title} to a new domain or build a creative extension.`,
89
+ deliverables: [
90
+ {
91
+ id: `${id}-d5`,
92
+ title: "Transfer Report",
93
+ description: `Choose a domain from ${topic.interdisciplinaryHooks.join(", ")} and build an explicit bridge.`,
94
+ format: "analysis",
95
+ minWords: 300,
96
+ rubric: [
97
+ "Chooses a specific external domain",
98
+ "Identifies structural similarities",
99
+ "Acknowledges where the analogy breaks",
100
+ "Proposes a novel insight or question"
101
+ ]
102
+ }
103
+ ],
104
+ estimatedHours: 3,
105
+ prerequisites: [],
106
+ status: "not_started"
107
+ },
108
+ {
109
+ id: `${id}-m4`,
110
+ title: "Teach-Back",
111
+ description: `Teach ${topic.title} to another learner. Teaching is the ultimate test of understanding.`,
112
+ deliverables: [
113
+ {
114
+ id: `${id}-d6`,
115
+ title: "Teaching Artifact",
116
+ description: `Create a teaching artifact: slides, blog post, video script, or interactive demo.`,
117
+ format: "presentation",
118
+ rubric: [
119
+ "Intuition comes before formalism",
120
+ "At least 2 examples (one simple, one complex)",
121
+ "Common misconception addressed explicitly",
122
+ "Includes a reflection question for the student"
123
+ ]
124
+ }
125
+ ],
126
+ estimatedHours: 4,
127
+ prerequisites: [],
128
+ status: "not_started"
129
+ }
130
+ ];
131
+ return {
132
+ id,
133
+ title: `${topic.title} Mastery Project`,
134
+ topic: topic.title,
135
+ slug: topic.slug,
136
+ description: `A comprehensive project to master ${topic.title} through research, practice, transfer, and teaching.`,
137
+ learningObjectives: [
138
+ `Define ${topic.title} precisely`,
139
+ `Apply ${topic.title} to solve unfamiliar problems`,
140
+ `Transfer ${topic.title} to at least one new domain`,
141
+ `Teach ${topic.title} to someone with no prior exposure`
142
+ ],
143
+ milestones,
144
+ totalEstimatedHours: milestones.reduce((s, m) => s + m.estimatedHours, 0),
145
+ generatedAt: new Date().toISOString()
146
+ };
147
+ }
148
+ // ─── Assignment Generation ────────────────────────────────────────────────
149
+ export function generateAssignment(topicName) {
150
+ const topic = resolveTopic(topicName);
151
+ const id = `asgn-${topic.slug}-${Date.now().toString(36)}`;
152
+ return {
153
+ id,
154
+ slug: topic.slug,
155
+ title: `${topic.title} Challenge`,
156
+ topic: topic.title,
157
+ instructions: `Complete all deliverables below. Focus on understanding, not speed. If you are stuck for more than 20 minutes, ask for help rather than guessing.`,
158
+ deliverables: [
159
+ {
160
+ id: `${id}-d1`,
161
+ title: "Core Analysis",
162
+ description: `Analyze ${topic.title} using formal definitions. Show your reasoning chain.`,
163
+ format: "essay",
164
+ minWords: 250,
165
+ rubric: [
166
+ "Uses correct formal definitions",
167
+ "Logic is sequential and verifiable",
168
+ "Assumptions are stated explicitly",
169
+ "Conclusion is supported by evidence"
170
+ ]
171
+ },
172
+ {
173
+ id: `${id}-d2`,
174
+ title: "Creative Extension",
175
+ description: `Propose a question, extension, or application of ${topic.title} that is NOT covered in standard textbooks.`,
176
+ format: "analysis",
177
+ rubric: [
178
+ "Question is genuinely novel",
179
+ "Builds on core concepts",
180
+ "Is answerable with reasonable effort",
181
+ "Author demonstrates awareness of what they do not yet know"
182
+ ]
183
+ }
184
+ ],
185
+ dueInDays: 7,
186
+ rubric: [
187
+ "All deliverables present and complete",
188
+ "Demonstrates original thinking, not paraphrasing",
189
+ "Acknowledges uncertainty where appropriate",
190
+ "Written in learner's own voice"
191
+ ],
192
+ generatedAt: new Date().toISOString()
193
+ };
194
+ }
195
+ // ─── Markdown output ──────────────────────────────────────────────────────
196
+ export function projectToMarkdown(project) {
197
+ const lines = [
198
+ `# Project: ${project.title}`,
199
+ "",
200
+ project.description,
201
+ "",
202
+ `**Estimated time:** ${project.totalEstimatedHours} hours`,
203
+ `**ID:** ${project.id}`,
204
+ "",
205
+ "## Learning Objectives",
206
+ "",
207
+ ...project.learningObjectives.map(o => `- ${o}`),
208
+ ""
209
+ ];
210
+ for (const m of project.milestones) {
211
+ lines.push(`---`);
212
+ lines.push(`# Milestone: ${m.title}`);
213
+ lines.push(m.description);
214
+ lines.push(`**Status:** ${m.status} | **Estimated:** ${m.estimatedHours}h`);
215
+ if (m.prerequisites.length > 0) {
216
+ lines.push(`**Prerequisites:** ${m.prerequisites.join(", ")}`);
217
+ }
218
+ lines.push("");
219
+ for (const d of m.deliverables) {
220
+ lines.push(`### ${d.title}`);
221
+ lines.push(d.description);
222
+ if (d.minWords)
223
+ lines.push(`*Minimum length:* ${d.minWords} words`);
224
+ lines.push("**Rubric:**");
225
+ for (const r of d.rubric)
226
+ lines.push(`- [ ] ${r}`);
227
+ lines.push("");
228
+ }
229
+ }
230
+ return lines.join("\n") + "\n";
231
+ }
232
+ export function assignmentToMarkdown(assignment) {
233
+ const lines = [
234
+ `# Assignment: ${assignment.title}`,
235
+ "",
236
+ assignment.instructions,
237
+ `**Due in:** ${assignment.dueInDays} days`,
238
+ "",
239
+ "## Deliverables",
240
+ ""
241
+ ];
242
+ for (const d of assignment.deliverables) {
243
+ lines.push(`### ${d.title}`);
244
+ lines.push(d.description);
245
+ if (d.minWords)
246
+ lines.push(`*Minimum:* ${d.minWords} words`);
247
+ lines.push("**Rubric:**");
248
+ for (const r of d.rubric)
249
+ lines.push(`- [ ] ${r}`);
250
+ lines.push("");
251
+ }
252
+ lines.push("## Overall Rubric");
253
+ for (const r of assignment.rubric)
254
+ lines.push(`- [ ] ${r}`);
255
+ lines.push("");
256
+ return lines.join("\n") + "\n";
257
+ }
258
+ export function computeProjectProgress(project) {
259
+ const totalMilestones = project.milestones.length;
260
+ const completedMilestones = project.milestones.filter(m => m.status === "reviewed").length;
261
+ const totalDeliverables = project.milestones.reduce((s, m) => s + m.deliverables.length, 0);
262
+ const completedDeliverables = project.milestones
263
+ .filter(m => m.status === "reviewed")
264
+ .reduce((s, m) => s + m.deliverables.length, 0);
265
+ const hours = project.milestones.reduce((s, m) => s + (m.status !== "not_started" ? m.estimatedHours : 0), 0);
266
+ let overall = "not_started";
267
+ if (completedMilestones === totalMilestones)
268
+ overall = "completed";
269
+ else if (completedMilestones > 0 || project.milestones.some(m => m.status === "in_progress"))
270
+ overall = "in_progress";
271
+ return {
272
+ projectId: project.id,
273
+ milestonesCompleted: completedMilestones,
274
+ milestonesTotal: totalMilestones,
275
+ deliverablesCompleted: completedDeliverables,
276
+ deliverablesTotal: totalDeliverables,
277
+ hoursLogged: hours,
278
+ overallStatus: overall,
279
+ lastActivityAt: new Date().toISOString()
280
+ };
281
+ }
@@ -0,0 +1,344 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { loadEnv } from "./env.js";
4
+ import { promptEvolutionArchivePath, promptEvolutionDir } from "./paths.js";
5
+ import { piComplete, piCompleteJson } from "./pi-agent.js";
6
+ loadEnv();
7
+ const KEATING_QUOTE = "Boys, you must strive to find your own voice. Because the longer you wait to begin, the less likely you are to find it at all.";
8
+ let piAvailabilityCache = null;
9
+ function promptNameFromPath(promptPath) {
10
+ const fileName = promptPath.split(/[\\/]/).pop() ?? promptPath;
11
+ return fileName.replace(/\.md$/, "");
12
+ }
13
+ function parsePromptBody(raw) {
14
+ if (!raw.startsWith("---"))
15
+ return raw.trim();
16
+ const parts = raw.split("\n---\n");
17
+ if (parts.length < 2)
18
+ return raw.trim();
19
+ return parts.slice(1).join("\n---\n").trim();
20
+ }
21
+ function parseFrontMatter(raw) {
22
+ if (!raw.startsWith("---"))
23
+ return "";
24
+ const parts = raw.split("\n---\n");
25
+ if (parts.length < 2)
26
+ return "";
27
+ return `${parts[0]}\n---`.trim();
28
+ }
29
+ function clamp01(value) {
30
+ return Math.max(0, Math.min(1, value));
31
+ }
32
+ function keywordScore(body, keywords, base, bonus) {
33
+ const hits = keywords.filter((keyword) => body.includes(keyword)).length;
34
+ return clamp01(base + hits * bonus);
35
+ }
36
+ function heuristicPromptEvaluation(promptPath, prompt) {
37
+ const body = parsePromptBody(prompt).toLowerCase();
38
+ const objectives = {
39
+ voice_divergence: keywordScore(body, ["own words", "own language", "personal context", "say it again"], 0.35, 0.18),
40
+ diagnosis: keywordScore(body, ["diagnostic", "prerequisite", "misconception", "assumption check"], 0.4, 0.16),
41
+ verification: keywordScore(body, ["verify", "verification", "source", "unverified", "check claim"], 0.2, 0.18),
42
+ retrieval: keywordScore(body, ["retrieval", "reconstruct", "without looking", "recall", "practice"], 0.35, 0.18),
43
+ transfer: keywordScore(body, ["transfer", "bridge", "other domain", "practical consequence", "new setting"], 0.3, 0.18),
44
+ structure: keywordScore(body, ["diagnose", "intuition", "formal", "misconception", "example", "retrieval", "reflection"], 0.45, 0.09)
45
+ };
46
+ const feedback = [];
47
+ if (objectives.voice_divergence < 0.7)
48
+ feedback.push("Add an explicit requirement that the learner restate the idea in their own words.");
49
+ if (objectives.diagnosis < 0.7)
50
+ feedback.push("Strengthen diagnosis of prerequisite gaps and misconceptions before teaching.");
51
+ if (objectives.verification < 0.7)
52
+ feedback.push("Include a step that distinguishes verified claims from claims that still need checking.");
53
+ if (objectives.retrieval < 0.7)
54
+ feedback.push("Add a retrieval checkpoint that requires reconstruction rather than agreement.");
55
+ if (objectives.transfer < 0.7)
56
+ feedback.push("Bridge the concept into a different domain or practical context before ending.");
57
+ if (objectives.structure < 0.7)
58
+ feedback.push("Make the lesson loop explicit so the workflow is easy to follow and evaluate.");
59
+ const score = objectives.voice_divergence * 14 +
60
+ objectives.diagnosis * 20 +
61
+ objectives.verification * 18 +
62
+ objectives.retrieval * 18 +
63
+ objectives.transfer * 16 +
64
+ objectives.structure * 14;
65
+ return {
66
+ promptPath,
67
+ promptName: promptNameFromPath(promptPath),
68
+ score,
69
+ objectives,
70
+ feedback
71
+ };
72
+ }
73
+ function heuristicCandidatePrompt(basePrompt) {
74
+ const frontMatter = parseFrontMatter(basePrompt);
75
+ const body = parsePromptBody(basePrompt).trimEnd();
76
+ const additions = [
77
+ '4a. If the learner echoes your phrasing, stop and ask them to explain the idea again in their own words.',
78
+ '4b. Separate missing prerequisite, misconception, and partial intuition before choosing the next teaching move.',
79
+ '5a. Add one short retrieval checkpoint that the learner must answer without relying on your wording.',
80
+ '6a. Bridge the idea into a new domain, personal example, or practical consequence before ending.',
81
+ '6b. Mark any factual claim that still needs verification instead of presenting it as settled.'
82
+ ].filter((line) => !body.includes(line));
83
+ const evolvedBody = additions.length === 0 ? `${body}\n7a. Keep the learner cognitively active at every step.` : `${body}\n${additions.join("\n")}`;
84
+ return frontMatter ? `${frontMatter}\n${evolvedBody}\n` : `${evolvedBody}\n`;
85
+ }
86
+ export async function evaluatePromptContent(cwd, promptPath, prompt) {
87
+ const body = parsePromptBody(prompt);
88
+ const evalPrompt = `Evaluate the following teaching prompt template based on Keating's hyperteacher philosophy.
89
+ Keating philosophy:
90
+ - AI must not be a surrogate for thought.
91
+ - Measuring success by the learner's independent articulation (finding their "voice").
92
+ - Rejecting "surface agreement" (rote echoes or simple "yes/no" answers).
93
+ - The "diagnose -> intuition -> formal core -> misconception repair -> example -> retrieval -> reflection" loop.
94
+
95
+ Evaluate these objectives on a scale of 0 to 1 (floating point):
96
+ 1. voice_divergence: How well does the prompt force the learner to use their own language? Penalize prompts that allow the learner to echo the AI's explanation.
97
+ 2. diagnosis: Checking prerequisites and misconceptions before teaching.
98
+ 3. verification: Refusing to teach unverified claims as settled truth.
99
+ 4. retrieval: Using reconstruction and practice instead of passive agreement.
100
+ 5. transfer: Bridging the concept to other domains or practical consequences.
101
+ 6. structure: Having an explicit, logical teaching workflow.
102
+
103
+ Provide the evaluation in JSON format:
104
+ {
105
+ "objectives": {
106
+ "voice_divergence": number,
107
+ "diagnosis": number,
108
+ "verification": number,
109
+ "retrieval": number,
110
+ "transfer": number,
111
+ "structure": number
112
+ },
113
+ "feedback": string[]
114
+ }
115
+
116
+ Prompt Content:
117
+ """
118
+ ${body}
119
+ """
120
+ `;
121
+ if (piAvailabilityCache === false) {
122
+ return heuristicPromptEvaluation(promptPath, prompt);
123
+ }
124
+ let data;
125
+ try {
126
+ data = await piCompleteJson(cwd, evalPrompt, { thinking: "low" });
127
+ piAvailabilityCache = true;
128
+ }
129
+ catch {
130
+ piAvailabilityCache = false;
131
+ const heuristic = heuristicPromptEvaluation(promptPath, prompt);
132
+ return heuristic;
133
+ }
134
+ // Guard against missing objectives in response
135
+ if (!data?.objectives) {
136
+ return heuristicPromptEvaluation(promptPath, prompt);
137
+ }
138
+ const objectives = data.objectives;
139
+ const score = objectives.voice_divergence * 14 +
140
+ objectives.diagnosis * 20 +
141
+ objectives.verification * 18 +
142
+ objectives.retrieval * 18 +
143
+ objectives.transfer * 16 +
144
+ objectives.structure * 14;
145
+ return {
146
+ promptPath,
147
+ promptName: promptNameFromPath(promptPath),
148
+ score,
149
+ objectives,
150
+ feedback: data.feedback
151
+ };
152
+ }
153
+ async function generateCandidatePrompt(cwd, basePrompt, evaluation, iteration) {
154
+ const frontMatter = parseFrontMatter(basePrompt);
155
+ const body = parsePromptBody(basePrompt);
156
+ const generationPrompt = `You are Keating's prompt-learning agent. Your goal is to evolve a teaching prompt template so that it prevents "surface agreement" and forces the learner to find their own voice.
157
+
158
+ Original Prompt:
159
+ """
160
+ ${body}
161
+ """
162
+
163
+ Feedback:
164
+ ${evaluation.feedback.map(f => `- ${f}`).join("\n")}
165
+
166
+ Mandate:
167
+ 1. PUSH FOR DIVERGENCE: Add instructions that force the learner to re-explain the concept using their own analogies or personal context.
168
+ 2. REJECT ECHOES: Instruct the teacher to identify if the learner is just repeating words from the previous explanation and, if so, ask them to "say it again, but as if you're explaining it to someone else entirely."
169
+ 3. ADDRESS FEEDBACK: Address the specific gaps in diagnosis, verification, and structure.
170
+
171
+ Evolved Prompt Body (no code blocks, no frontmatter):`;
172
+ if (piAvailabilityCache === false) {
173
+ return heuristicCandidatePrompt(basePrompt);
174
+ }
175
+ let evolvedBody;
176
+ try {
177
+ evolvedBody = await piComplete(cwd, generationPrompt, { thinking: "medium" });
178
+ piAvailabilityCache = true;
179
+ }
180
+ catch {
181
+ piAvailabilityCache = false;
182
+ return heuristicCandidatePrompt(basePrompt);
183
+ }
184
+ return frontMatter ? `${frontMatter}\n${evolvedBody}\n` : `${evolvedBody}\n`;
185
+ }
186
+ function objectiveVector(candidate) {
187
+ const { objectives } = candidate.evaluation;
188
+ return [
189
+ objectives.voice_divergence,
190
+ objectives.diagnosis,
191
+ objectives.verification,
192
+ objectives.retrieval,
193
+ objectives.transfer,
194
+ objectives.structure
195
+ ];
196
+ }
197
+ function pairwisePreference(left, right) {
198
+ const leftVector = objectiveVector(left);
199
+ const rightVector = objectiveVector(right);
200
+ let wins = 0;
201
+ let losses = 0;
202
+ for (let index = 0; index < leftVector.length; index += 1) {
203
+ if (leftVector[index] > rightVector[index])
204
+ wins += 1;
205
+ if (leftVector[index] < rightVector[index])
206
+ losses += 1;
207
+ }
208
+ const aggregateDelta = left.evaluation.score - right.evaluation.score;
209
+ return wins - losses + aggregateDelta / 25;
210
+ }
211
+ export function prosperStyleWinner(candidates) {
212
+ let best = candidates[0];
213
+ let bestScore = -Infinity;
214
+ for (const candidate of candidates) {
215
+ const score = candidates.reduce((sum, opponent) => {
216
+ if (candidate === opponent)
217
+ return sum;
218
+ return sum + pairwisePreference(candidate, opponent);
219
+ }, 0);
220
+ candidate.preferenceScore = score;
221
+ if (score > bestScore) {
222
+ best = candidate;
223
+ bestScore = score;
224
+ }
225
+ }
226
+ return best;
227
+ }
228
+ async function loadArchive(archivePath) {
229
+ try {
230
+ const raw = await readFile(archivePath, "utf8");
231
+ return JSON.parse(raw);
232
+ }
233
+ catch {
234
+ return { winners: [] };
235
+ }
236
+ }
237
+ async function saveArchive(archivePath, archive) {
238
+ await writeFile(archivePath, `${JSON.stringify(archive, null, 2)}\n`, "utf8");
239
+ }
240
+ export async function evolvePrompt(cwd, promptName = "learn", iterations = 4, evaluator = evaluatePromptContent, generator = generateCandidatePrompt) {
241
+ const promptPath = join(cwd, "pi", "prompts", `${promptName}.md`);
242
+ const prompt = await readFile(promptPath, "utf8");
243
+ const baseline = await evaluator(cwd, promptPath, prompt);
244
+ const candidates = [];
245
+ for (let iteration = 1; iteration <= iterations; iteration += 1) {
246
+ const candidatePrompt = await generator(cwd, prompt, baseline, iteration);
247
+ const evaluation = await evaluator(cwd, promptPath, candidatePrompt);
248
+ candidates.push({
249
+ iteration,
250
+ label: `${promptName}-candidate-${iteration}`,
251
+ prompt: candidatePrompt,
252
+ evaluation,
253
+ parentLabel: promptName,
254
+ accepted: false,
255
+ preferenceScore: 0
256
+ });
257
+ }
258
+ const best = prosperStyleWinner(candidates);
259
+ for (const candidate of candidates) {
260
+ candidate.accepted = candidate.label === best.label && candidate.evaluation.score >= baseline.score;
261
+ }
262
+ const archivePath = promptEvolutionArchivePath(cwd);
263
+ const archive = await loadArchive(archivePath);
264
+ archive.winners.push({
265
+ promptName,
266
+ label: best.label,
267
+ score: best.evaluation.score,
268
+ objectives: best.evaluation.objectives,
269
+ updatedAt: new Date().toISOString()
270
+ });
271
+ await saveArchive(archivePath, archive);
272
+ return {
273
+ promptPath,
274
+ promptName,
275
+ baseline,
276
+ best,
277
+ exploredCandidates: candidates,
278
+ acceptedCandidates: candidates.filter((candidate) => candidate.accepted)
279
+ };
280
+ }
281
+ export async function writePromptEvolutionArtifacts(cwd, promptName = "learn") {
282
+ const run = await evolvePrompt(cwd, promptName);
283
+ const reportPath = join(promptEvolutionDir(cwd), `${promptName}.md`);
284
+ const evolvedPromptPath = join(promptEvolutionDir(cwd), `${promptName}.evolved.md`);
285
+ await writeFile(reportPath, promptEvolutionToMarkdown(run), "utf8");
286
+ await writeFile(evolvedPromptPath, run.best.prompt, "utf8");
287
+ return {
288
+ reportPath,
289
+ evolvedPromptPath,
290
+ bestScore: run.best.evaluation.score,
291
+ promptPath: run.promptPath
292
+ };
293
+ }
294
+ export function promptEvolutionToMarkdown(run) {
295
+ const objectiveList = (objectives) => [
296
+ `voice_divergence=${objectives.voice_divergence.toFixed(2)}`,
297
+ `diagnosis=${objectives.diagnosis.toFixed(2)}`,
298
+ `verification=${objectives.verification.toFixed(2)}`,
299
+ `retrieval=${objectives.retrieval.toFixed(2)}`,
300
+ `transfer=${objectives.transfer.toFixed(2)}`,
301
+ `structure=${objectives.structure.toFixed(2)}`
302
+ ];
303
+ const lines = [
304
+ `# Prompt Evolution Report: ${run.promptName}`,
305
+ "",
306
+ `- Source prompt: ${run.promptPath}`,
307
+ `- Baseline score: ${run.baseline.score.toFixed(2)}`,
308
+ `- Best candidate: ${run.best.label}`,
309
+ `- Best candidate score: ${run.best.evaluation.score.toFixed(2)}`,
310
+ `- PROSPER-style preference score: ${run.best.preferenceScore.toFixed(2)}`,
311
+ "",
312
+ "## Baseline Feedback",
313
+ ""
314
+ ];
315
+ if (run.baseline.feedback.length === 0) {
316
+ lines.push("- No major prompt-learning gaps detected.");
317
+ }
318
+ else {
319
+ for (const item of run.baseline.feedback) {
320
+ lines.push(`- ${item}`);
321
+ }
322
+ }
323
+ lines.push("");
324
+ lines.push("## Candidate Comparison");
325
+ lines.push("");
326
+ for (const candidate of run.exploredCandidates) {
327
+ lines.push(`### ${candidate.label}`);
328
+ lines.push(`- score: ${candidate.evaluation.score.toFixed(2)}`);
329
+ lines.push(`- preference: ${candidate.preferenceScore.toFixed(2)}`);
330
+ lines.push(`- accepted: ${candidate.accepted ? "yes" : "no"}`);
331
+ lines.push(`- objectives: ${objectiveList(candidate.evaluation.objectives).join(", ")}`);
332
+ lines.push("");
333
+ }
334
+ lines.push("## Recommended Prompt");
335
+ lines.push("```md");
336
+ lines.push(run.best.prompt.trimEnd());
337
+ lines.push("```");
338
+ lines.push("");
339
+ return `${lines.join("\n")}\n`;
340
+ }
341
+ import { learnPrompt } from "./ax-prompt-learner.js";
342
+ export async function evolveWithACE(cwd, promptName = "learn", options) {
343
+ return learnPrompt(cwd, promptName, options);
344
+ }