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.
- package/README.md +334 -0
- package/SYSTEM.md +33 -0
- package/bin/keating.js +31 -0
- package/dist/src/cli/main.js +357 -0
- package/dist/src/cli/setup.js +197 -0
- package/dist/src/cli/web.js +84 -0
- package/dist/src/core/animation.js +304 -0
- package/dist/src/core/ax-optimizer.js +81 -0
- package/dist/src/core/ax-prompt-learner.js +59 -0
- package/dist/src/core/ax-trial.js +181 -0
- package/dist/src/core/benchmark.js +253 -0
- package/dist/src/core/commands.js +57 -0
- package/dist/src/core/config.js +120 -0
- package/dist/src/core/engagement.js +235 -0
- package/dist/src/core/env.js +9 -0
- package/dist/src/core/evolution.js +242 -0
- package/dist/src/core/flashcards.js +133 -0
- package/dist/src/core/learner-state.js +108 -0
- package/dist/src/core/lesson-plan.js +155 -0
- package/dist/src/core/map-elites.js +228 -0
- package/dist/src/core/map.js +89 -0
- package/dist/src/core/mastery.js +207 -0
- package/dist/src/core/paths.js +100 -0
- package/dist/src/core/pi-agent.js +82 -0
- package/dist/src/core/policy.js +79 -0
- package/dist/src/core/project.js +337 -0
- package/dist/src/core/projects.js +281 -0
- package/dist/src/core/prompt-evolution.js +344 -0
- package/dist/src/core/quiz.js +194 -0
- package/dist/src/core/random.js +19 -0
- package/dist/src/core/self-improve.js +425 -0
- package/dist/src/core/speech.js +54 -0
- package/dist/src/core/terminal.js +117 -0
- package/dist/src/core/theme.js +101 -0
- package/dist/src/core/topics.js +620 -0
- package/dist/src/core/types.js +1 -0
- package/dist/src/core/util.js +30 -0
- package/dist/src/core/verification.js +162 -0
- package/dist/src/pi/hyperteacher-extension.js +573 -0
- package/dist/src/runtime/pi.js +343 -0
- package/package.json +78 -0
- package/pi/prompts/bridge.md +14 -0
- package/pi/prompts/diagnose.md +15 -0
- package/pi/prompts/improve.md +39 -0
- package/pi/prompts/learn.md +21 -0
- package/pi/prompts/quiz.md +14 -0
- package/pi/skills/adaptive-teaching/SKILL.md +33 -0
- package/scripts/install/install.sh +308 -0
- package/web/dist/.well-known/llms.txt +44 -0
- package/web/dist/apple-touch-icon.svg +10 -0
- package/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/web/dist/assets/_baseFor-B_cjfMB6.js +1 -0
- package/web/dist/assets/anthropic-BT6Vfzb1.js +36 -0
- package/web/dist/assets/arc-x2nTilpc.js +1 -0
- package/web/dist/assets/architecture-YZFGNWBL-B1hlUWjX.js +1 -0
- package/web/dist/assets/architectureDiagram-Q4EWVU46-CMApWFyw.js +36 -0
- package/web/dist/assets/array-B9UHiPd-.js +1 -0
- package/web/dist/assets/azure-openai-responses-CommX3YJ.js +1 -0
- package/web/dist/assets/blockDiagram-DXYQGD6D-DOQbsNRY.js +132 -0
- package/web/dist/assets/c4Diagram-AHTNJAMY-VFfRZWWA.js +10 -0
- package/web/dist/assets/channel-KY2Tg8Ba.js +1 -0
- package/web/dist/assets/chunk-2KRD3SAO-B-AqvS0u.js +1 -0
- package/web/dist/assets/chunk-336JU56O-DlYgPyl6.js +2 -0
- package/web/dist/assets/chunk-426QAEUC-CsVoBkfR.js +1 -0
- package/web/dist/assets/chunk-4BX2VUAB-0Z13aFAn.js +1 -0
- package/web/dist/assets/chunk-4TB4RGXK-DqC0Zwm7.js +206 -0
- package/web/dist/assets/chunk-55IACEB6-CWE_u-IY.js +1 -0
- package/web/dist/assets/chunk-5FUZZQ4R-CApli0xX.js +62 -0
- package/web/dist/assets/chunk-5PVQY5BW-Cbzhfhln.js +2 -0
- package/web/dist/assets/chunk-67CJDMHE-Cx7uJS4d.js +1 -0
- package/web/dist/assets/chunk-7N4EOEYR-CYPNsFus.js +1 -0
- package/web/dist/assets/chunk-AA7GKIK3-rU0uhR_u.js +1 -0
- package/web/dist/assets/chunk-BSJP7CBP-5VmcfR4-.js +1 -0
- package/web/dist/assets/chunk-Bj-mKKzh.js +1 -0
- package/web/dist/assets/chunk-CIAEETIT-CHJ-L8H1.js +1 -0
- package/web/dist/assets/chunk-EDXVE4YY-DZHAJjMI.js +1 -0
- package/web/dist/assets/chunk-ENJZ2VHE-DbUDFa7w.js +10 -0
- package/web/dist/assets/chunk-FMBD7UC4-BsYE5e_h.js +15 -0
- package/web/dist/assets/chunk-FOC6F5B3-Cm6aoTv7.js +1 -0
- package/web/dist/assets/chunk-ICPOFSXX-C5eNZ4L6.js +123 -0
- package/web/dist/assets/chunk-K5T4RW27-R7dAJ4rq.js +94 -0
- package/web/dist/assets/chunk-KGLVRYIC-MO99YZXL.js +1 -0
- package/web/dist/assets/chunk-LIHQZDEY-DUJ656sT.js +1 -0
- package/web/dist/assets/chunk-ORNJ4GCN-DXuuEC1n.js +1 -0
- package/web/dist/assets/chunk-OYMX7WX6-pJlEprWq.js +231 -0
- package/web/dist/assets/chunk-QZHKN3VN-_pQxbbiW.js +1 -0
- package/web/dist/assets/chunk-U2HBQHQK-Mh_l9PLe.js +70 -0
- package/web/dist/assets/chunk-X2U36JSP-BOeiJW0w.js +1 -0
- package/web/dist/assets/chunk-XPW4576I-fQ9SDvr_.js +32 -0
- package/web/dist/assets/chunk-YZCP3GAM-eboO4P5S.js +1 -0
- package/web/dist/assets/chunk-ZZ45TVLE-Cky0eqlr.js +1 -0
- package/web/dist/assets/classDiagram-6PBFFD2Q-DEPsZSU3.js +1 -0
- package/web/dist/assets/classDiagram-v2-HSJHXN6E-DhmIOEpX.js +1 -0
- package/web/dist/assets/clone-DeTzYqo8.js +1 -0
- package/web/dist/assets/cose-bilkent-S5V4N54A-N4zWUJ7C.js +1 -0
- package/web/dist/assets/cytoscape.esm-BBMd0vGm.js +321 -0
- package/web/dist/assets/dagre-IpK1aoMm.js +1 -0
- package/web/dist/assets/dagre-KV5264BT-DCytJuju.js +4 -0
- package/web/dist/assets/defaultLocale-5eAKkKJC.js +1 -0
- package/web/dist/assets/diagram-5BDNPKRD-Cv4miBae.js +10 -0
- package/web/dist/assets/diagram-G4DWMVQ6-CtICKUFi.js +24 -0
- package/web/dist/assets/diagram-MMDJMWI5-Cn7aGorh.js +43 -0
- package/web/dist/assets/diagram-TYMM5635-CCUWDPsC.js +24 -0
- package/web/dist/assets/dist-Dm98VvTW.js +1 -0
- package/web/dist/assets/env-api-keys-BNlMKqxw.js +1 -0
- package/web/dist/assets/erDiagram-SMLLAGMA-uT88sBlT.js +85 -0
- package/web/dist/assets/event-stream-D33K9rpL.js +1 -0
- package/web/dist/assets/flatten-C-u5nd5-.js +1 -0
- package/web/dist/assets/flowDiagram-DWJPFMVM-Bl3O7S1m.js +162 -0
- package/web/dist/assets/ganttDiagram-T4ZO3ILL-B1FhwV45.js +292 -0
- package/web/dist/assets/gitGraph-7Q5UKJZL-Bc_7vzer.js +1 -0
- package/web/dist/assets/gitGraphDiagram-UUTBAWPF-DfW6svMS.js +106 -0
- package/web/dist/assets/github-copilot-headers-L39QqneT.js +1 -0
- package/web/dist/assets/google-BdYNeCP_.js +1 -0
- package/web/dist/assets/google-gemini-cli-DpxAL3K4.js +2 -0
- package/web/dist/assets/google-shared-DyQdgtsI.js +2 -0
- package/web/dist/assets/google-vertex-CKRybaXj.js +1 -0
- package/web/dist/assets/graphlib-CMTVFyOZ.js +1 -0
- package/web/dist/assets/hash-kZ2KD_no.js +1 -0
- package/web/dist/assets/index-Bdb7P7gx.css +2 -0
- package/web/dist/assets/index-DNxepp8B.js +2891 -0
- package/web/dist/assets/info-OMHHGYJF-BGcxeaZt.js +1 -0
- package/web/dist/assets/infoDiagram-42DDH7IO-BbES7X_c.js +2 -0
- package/web/dist/assets/init-DlZdxViB.js +1 -0
- package/web/dist/assets/isEmpty-DssUW35f.js +1 -0
- package/web/dist/assets/ishikawaDiagram-UXIWVN3A-DxQ28rho.js +70 -0
- package/web/dist/assets/journeyDiagram-VCZTEJTY-D0X8qQ0P.js +139 -0
- package/web/dist/assets/json-parse-C6tSeIxX.js +2 -0
- package/web/dist/assets/kanban-definition-6JOO6SKY-DWYfSlpl.js +89 -0
- package/web/dist/assets/katex-CyM-5LlM.js +265 -0
- package/web/dist/assets/line-CuHce5JG.js +1 -0
- package/web/dist/assets/linear-Ca0Vkwuj.js +1 -0
- package/web/dist/assets/mermaid-parser.core-Cy4iY_Dy.js +4 -0
- package/web/dist/assets/mermaid.core-6PGkQdYc.js +11 -0
- package/web/dist/assets/mindmap-definition-QFDTVHPH-BBnKdtQh.js +96 -0
- package/web/dist/assets/mistral-BWaUMIgd.js +7 -0
- package/web/dist/assets/openai-D4NSaQIs.js +16 -0
- package/web/dist/assets/openai-codex-responses-CHBgKhmb.js +7 -0
- package/web/dist/assets/openai-completions-kcXmmaHI.js +5 -0
- package/web/dist/assets/openai-responses-Cqq3H3p3.js +1 -0
- package/web/dist/assets/openai-responses-shared-CTNuo9ci.js +10 -0
- package/web/dist/assets/ordinal-_K3x1fkz.js +1 -0
- package/web/dist/assets/ort-wasm-simd-threaded.jsep-B0T3yYHD.wasm +0 -0
- package/web/dist/assets/packet-4T2RLAQJ-D35ZLSBH.js +1 -0
- package/web/dist/assets/path-6uRLdFF7.js +1 -0
- package/web/dist/assets/pdf.worker.min-Cpi8b8z3.mjs +28 -0
- package/web/dist/assets/pie-ZZUOXDRM-DRoETpJX.js +1 -0
- package/web/dist/assets/pieDiagram-DEJITSTG-DfMjfTQz.js +30 -0
- package/web/dist/assets/preload-helper-DSXbuxSR.js +1 -0
- package/web/dist/assets/quadrantDiagram-34T5L4WZ-DfBSEept.js +7 -0
- package/web/dist/assets/radar-PYXPWWZC-DLKxRJ0V.js +1 -0
- package/web/dist/assets/reduce-836A2NiQ.js +1 -0
- package/web/dist/assets/requirementDiagram-MS252O5E-BPkxJQkz.js +84 -0
- package/web/dist/assets/rough.esm-Djo4Abte.js +1 -0
- package/web/dist/assets/sankeyDiagram-XADWPNL6-He3x9tNT.js +10 -0
- package/web/dist/assets/sequenceDiagram-FGHM5R23-DfCDpvrT.js +157 -0
- package/web/dist/assets/src-DdOdIreR.js +1 -0
- package/web/dist/assets/stateDiagram-FHFEXIEX-fuww6347.js +1 -0
- package/web/dist/assets/stateDiagram-v2-QKLJ7IA2-U6voafO3.js +1 -0
- package/web/dist/assets/timeline-definition-GMOUNBTQ-BWunHgBC.js +120 -0
- package/web/dist/assets/transform-messages-CqKEdRVp.js +1 -0
- package/web/dist/assets/transformers.web-DKUtmSAi.js +2818 -0
- package/web/dist/assets/treeView-SZITEDCU-BCx0xSAm.js +1 -0
- package/web/dist/assets/treemap-W4RFUUIX-2CvghWJK.js +1 -0
- package/web/dist/assets/vennDiagram-DHZGUBPP-CBXRutSP.js +34 -0
- package/web/dist/assets/wardley-RL74JXVD-BkPL_mhd.js +1 -0
- package/web/dist/assets/wardleyDiagram-NUSXRM2D-DTcVscPH.js +20 -0
- package/web/dist/assets/web-CMKYLKbT.js +10 -0
- package/web/dist/assets/xychartDiagram-5P7HB3ND-CZLgX9Fe.js +7 -0
- package/web/dist/favicon.svg +10 -0
- package/web/dist/index.html +104 -0
- package/web/dist/keating-metaharness.pdf +10557 -3
- package/web/dist/llms.txt +44 -0
- package/web/dist/logo.png +0 -0
- package/web/dist/manifest.webmanifest +1 -0
- package/web/dist/og-image.png +0 -0
- package/web/dist/pwa-192x192.svg +10 -0
- package/web/dist/pwa-512x512.svg +10 -0
- package/web/dist/registerSW.js +1 -0
- package/web/dist/robots.txt +8 -0
- package/web/dist/sitemap.xml +39 -0
- package/web/dist/sw.js +1 -0
- package/web/dist/tapes/doctor.mp4 +0 -0
- package/web/dist/tapes/feedback-flow.mp4 +0 -0
- package/web/dist/tapes/improve-flow.mp4 +0 -0
- package/web/dist/tapes/intro.mp4 +0 -0
- package/web/dist/tapes/learning-flow.mp4 +0 -0
- package/web/dist/tapes/session-flow.mp4 +0 -0
- package/web/dist/tapes/teacher-flow.mp4 +0 -0
- package/web/dist/tapes/tests.mp4 +0 -0
- package/web/dist/workbox-66610c77.js +1 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { loadKeatingConfig, mergePiDefaults } from "./config.js";
|
|
3
|
+
import { configDir } from "./paths.js";
|
|
4
|
+
import { detectAiRuntime } from "../runtime/pi.js";
|
|
5
|
+
/**
|
|
6
|
+
* Programmatic interface to the AI agent via CLI.
|
|
7
|
+
* This ensures we use the same provider, model, and thinking settings as the user's agent install.
|
|
8
|
+
*/
|
|
9
|
+
export async function piComplete(cwd, prompt, options = {}) {
|
|
10
|
+
const config = await loadKeatingConfig(cwd);
|
|
11
|
+
const runtime = await detectAiRuntime(cwd);
|
|
12
|
+
if (!runtime.selected) {
|
|
13
|
+
throw new Error("No AI runtime found. Install `pi` with `npm install -g @mariozechner/pi-coding-agent`, or reinstall Keating so its embedded runtime dependency is present.");
|
|
14
|
+
}
|
|
15
|
+
const args = ["-p", "--no-session", "--no-tools", "--no-extensions", "--no-skills"];
|
|
16
|
+
if (options.systemPrompt) {
|
|
17
|
+
args.push("--system-prompt", options.systemPrompt);
|
|
18
|
+
}
|
|
19
|
+
if (options.json) {
|
|
20
|
+
args.push("--mode", "json");
|
|
21
|
+
}
|
|
22
|
+
if (options.thinking) {
|
|
23
|
+
args.push("--thinking", options.thinking);
|
|
24
|
+
}
|
|
25
|
+
const finalArgs = mergePiDefaults(config, [...args, prompt]);
|
|
26
|
+
let result;
|
|
27
|
+
try {
|
|
28
|
+
const isBinary = runtime.selected.kind === "binary";
|
|
29
|
+
const command = runtime.selected.command;
|
|
30
|
+
const spawnArgs = isBinary ? finalArgs : [runtime.selected.cliPath, ...finalArgs];
|
|
31
|
+
result = spawnSync(command, spawnArgs, {
|
|
32
|
+
cwd,
|
|
33
|
+
stdio: "pipe",
|
|
34
|
+
encoding: "utf8",
|
|
35
|
+
env: {
|
|
36
|
+
...process.env,
|
|
37
|
+
PI_SKIP_VERSION_CHECK: "1",
|
|
38
|
+
PI_CODING_AGENT_DIR: configDir(cwd)
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
throw new Error(`Agent command could not be spawned: ${e}`);
|
|
44
|
+
}
|
|
45
|
+
if (result.error) {
|
|
46
|
+
throw new Error(`Agent command failed to launch: ${result.error.message}`);
|
|
47
|
+
}
|
|
48
|
+
const signal = result.signal;
|
|
49
|
+
const exitStatus = result.status;
|
|
50
|
+
if (exitStatus === null || exitStatus !== 0) {
|
|
51
|
+
const errMsg = result.stderr?.trim() || result.stdout?.trim() || "unknown error";
|
|
52
|
+
const exitInfo = exitStatus !== null ? `exit ${exitStatus}` : `killed by signal ${signal ?? "unknown"}`;
|
|
53
|
+
throw new Error(`Agent completion failed (${exitInfo}): ${errMsg}`);
|
|
54
|
+
}
|
|
55
|
+
return result.stdout.trim();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Specialized helper for JSON completions.
|
|
59
|
+
*/
|
|
60
|
+
export async function piCompleteJson(cwd, prompt, options = {}) {
|
|
61
|
+
const response = await piComplete(cwd, prompt, { ...options, json: true });
|
|
62
|
+
try {
|
|
63
|
+
// Some models output reasoning BEFORE the JSON block.
|
|
64
|
+
// We try to find all JSON-like blocks and pick the one that parses successfully,
|
|
65
|
+
// prioritizing the last one.
|
|
66
|
+
const matches = response.match(/\{[\s\S]*?\}/g);
|
|
67
|
+
if (!matches)
|
|
68
|
+
return JSON.parse(response);
|
|
69
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(matches[i]);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw new Error("No valid JSON block found in response.");
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw new Error(`Failed to parse agent JSON response: ${response}\nError: ${error}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { clamp } from "./util.js";
|
|
3
|
+
export const DEFAULT_POLICY = {
|
|
4
|
+
name: "keating-default",
|
|
5
|
+
analogyDensity: 0.72,
|
|
6
|
+
socraticRatio: 0.66,
|
|
7
|
+
formalism: 0.64,
|
|
8
|
+
retrievalPractice: 0.74,
|
|
9
|
+
exerciseCount: 3,
|
|
10
|
+
diagramBias: 0.7,
|
|
11
|
+
reflectionBias: 0.68,
|
|
12
|
+
interdisciplinaryBias: 0.62,
|
|
13
|
+
challengeRate: 0.58
|
|
14
|
+
};
|
|
15
|
+
export const DEFAULT_WEIGHTS = {
|
|
16
|
+
masteryGain: 0.34,
|
|
17
|
+
retention: 0.20,
|
|
18
|
+
engagement: 0.16,
|
|
19
|
+
transfer: 0.18,
|
|
20
|
+
confusion: 0.18
|
|
21
|
+
};
|
|
22
|
+
export function clampWeights(weights) {
|
|
23
|
+
const clamped = {
|
|
24
|
+
masteryGain: clamp(weights.masteryGain, 0.01, 1),
|
|
25
|
+
retention: clamp(weights.retention, 0.01, 1),
|
|
26
|
+
engagement: clamp(weights.engagement, 0.01, 1),
|
|
27
|
+
transfer: clamp(weights.transfer, 0.01, 1),
|
|
28
|
+
confusion: clamp(weights.confusion, 0.01, 1)
|
|
29
|
+
};
|
|
30
|
+
const sum = clamped.masteryGain + clamped.retention + clamped.engagement + clamped.transfer + clamped.confusion;
|
|
31
|
+
if (sum === 0)
|
|
32
|
+
return DEFAULT_WEIGHTS;
|
|
33
|
+
return {
|
|
34
|
+
masteryGain: clamped.masteryGain / sum,
|
|
35
|
+
retention: clamped.retention / sum,
|
|
36
|
+
engagement: clamped.engagement / sum,
|
|
37
|
+
transfer: clamped.transfer / sum,
|
|
38
|
+
confusion: clamped.confusion / sum
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function clampPolicy(policy) {
|
|
42
|
+
return {
|
|
43
|
+
...policy,
|
|
44
|
+
analogyDensity: clamp(policy.analogyDensity),
|
|
45
|
+
socraticRatio: clamp(policy.socraticRatio),
|
|
46
|
+
formalism: clamp(policy.formalism),
|
|
47
|
+
retrievalPractice: clamp(policy.retrievalPractice),
|
|
48
|
+
exerciseCount: Math.min(5, Math.max(1, Math.round(policy.exerciseCount))),
|
|
49
|
+
diagramBias: clamp(policy.diagramBias),
|
|
50
|
+
reflectionBias: clamp(policy.reflectionBias),
|
|
51
|
+
interdisciplinaryBias: clamp(policy.interdisciplinaryBias),
|
|
52
|
+
challengeRate: clamp(policy.challengeRate)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function policySignature(policy) {
|
|
56
|
+
return [
|
|
57
|
+
policy.analogyDensity.toFixed(2),
|
|
58
|
+
policy.socraticRatio.toFixed(2),
|
|
59
|
+
policy.formalism.toFixed(2),
|
|
60
|
+
policy.retrievalPractice.toFixed(2),
|
|
61
|
+
String(policy.exerciseCount),
|
|
62
|
+
policy.diagramBias.toFixed(2),
|
|
63
|
+
policy.reflectionBias.toFixed(2),
|
|
64
|
+
policy.interdisciplinaryBias.toFixed(2),
|
|
65
|
+
policy.challengeRate.toFixed(2)
|
|
66
|
+
].join("|");
|
|
67
|
+
}
|
|
68
|
+
export async function loadPolicy(filePath) {
|
|
69
|
+
try {
|
|
70
|
+
const content = await readFile(filePath, "utf8");
|
|
71
|
+
return clampPolicy(JSON.parse(content));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return DEFAULT_POLICY;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export async function savePolicy(filePath, policy) {
|
|
78
|
+
await writeFile(filePath, `${JSON.stringify(clampPolicy(policy), null, 2)}\n`, "utf8");
|
|
79
|
+
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { readdir, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { loadKeatingConfig } from "./config.js";
|
|
4
|
+
import { writeLessonAnimation } from "./animation.js";
|
|
5
|
+
import { benchmarkToMarkdown, runBenchmarkSuite } from "./benchmark.js";
|
|
6
|
+
import { buildEngagementTimeline, dueTopics, dueTopicsToMarkdown, engagementTimelineToMarkdown, loadEngagementPolicy } from "./engagement.js";
|
|
7
|
+
import { mapElitesEvolve, mapElitesToMarkdown, mapElitesToEvolutionRun } from "./map-elites.js";
|
|
8
|
+
import { buildLessonPlan, lessonPlanToMarkdown } from "./lesson-plan.js";
|
|
9
|
+
import { writeLessonMap } from "./map.js";
|
|
10
|
+
import { evaluatePromptContent, writePromptEvolutionArtifacts } from "./prompt-evolution.js";
|
|
11
|
+
import { animationsDir, benchmarksDir, currentPolicyPath, ensureKeatingDirs, engagementPolicyPath, evolutionDir, mapsDir, plansDir, promptEvolutionDir, timelineDir, tracesDir, verificationsDir, verificationCachePath, learnerStatePath, quizDir, flashcardsDir, projectsDir, workbooksDir, masteryDir } from "./paths.js";
|
|
12
|
+
import { ensureConfig } from "./config.js";
|
|
13
|
+
import { DEFAULT_POLICY, loadPolicy, savePolicy } from "./policy.js";
|
|
14
|
+
import { resolveTopic } from "./topics.js";
|
|
15
|
+
import { slugify } from "./util.js";
|
|
16
|
+
import { buildPendingVerificationResult, buildVerificationChecklist, loadVerificationCache, runCoveVerification, saveVerificationCache, verificationStatus } from "./verification.js";
|
|
17
|
+
import { loadLearnerState } from "./learner-state.js";
|
|
18
|
+
import { generateImprovementArtifact, loadImprovementArchive, improvementHistoryToMarkdown, evaluateImprovement, acceptImprovement, rejectImprovement } from "./self-improve.js";
|
|
19
|
+
import { generateQuiz, quizToMarkdown, quizAnswerKeyToMarkdown, generateWorkbook, workbookToMarkdown } from "./quiz.js";
|
|
20
|
+
import { generateFlashCards, flashcardsToMarkdown } from "./flashcards.js";
|
|
21
|
+
import { generateProject, generateAssignment, projectToMarkdown, assignmentToMarkdown } from "./projects.js";
|
|
22
|
+
import { generateDiagnosticQuestions } from "./mastery.js";
|
|
23
|
+
export async function ensureProjectScaffold(cwd) {
|
|
24
|
+
await ensureKeatingDirs(cwd);
|
|
25
|
+
await ensureConfig(cwd);
|
|
26
|
+
const policy = await loadPolicy(currentPolicyPath(cwd));
|
|
27
|
+
await savePolicy(currentPolicyPath(cwd), policy ?? DEFAULT_POLICY);
|
|
28
|
+
}
|
|
29
|
+
export async function planTopicArtifact(cwd, topicName) {
|
|
30
|
+
await ensureProjectScaffold(cwd);
|
|
31
|
+
const policy = await loadPolicy(currentPolicyPath(cwd));
|
|
32
|
+
const plan = buildLessonPlan(topicName, policy);
|
|
33
|
+
const planPath = join(plansDir(cwd), `${slugify(topicName)}.md`);
|
|
34
|
+
await writeFile(planPath, lessonPlanToMarkdown(plan), "utf8");
|
|
35
|
+
return { planPath };
|
|
36
|
+
}
|
|
37
|
+
export async function mapTopicArtifact(cwd, topicName) {
|
|
38
|
+
await ensureProjectScaffold(cwd);
|
|
39
|
+
const policy = await loadPolicy(currentPolicyPath(cwd));
|
|
40
|
+
return writeLessonMap(cwd, topicName, policy);
|
|
41
|
+
}
|
|
42
|
+
export async function animateTopicArtifact(cwd, topicName) {
|
|
43
|
+
await ensureProjectScaffold(cwd);
|
|
44
|
+
const policy = await loadPolicy(currentPolicyPath(cwd));
|
|
45
|
+
return writeLessonAnimation(cwd, topicName, policy);
|
|
46
|
+
}
|
|
47
|
+
export async function benchPolicyArtifact(cwd, focusTopic) {
|
|
48
|
+
await ensureProjectScaffold(cwd);
|
|
49
|
+
const config = await loadKeatingConfig(cwd);
|
|
50
|
+
const policy = await loadPolicy(currentPolicyPath(cwd));
|
|
51
|
+
const result = await runBenchmarkSuite(cwd, policy, focusTopic, 20260401, config.debug.traceTopLearners);
|
|
52
|
+
const fileName = focusTopic ? `${slugify(focusTopic)}.md` : "core-suite.md";
|
|
53
|
+
const reportPath = join(benchmarksDir(cwd), fileName);
|
|
54
|
+
await writeFile(reportPath, benchmarkToMarkdown(result), "utf8");
|
|
55
|
+
const tracePath = config.debug.persistTraces
|
|
56
|
+
? join(tracesDir(cwd), `${focusTopic ? slugify(focusTopic) : "core-suite"}-benchmark.json`)
|
|
57
|
+
: null;
|
|
58
|
+
if (tracePath) {
|
|
59
|
+
await writeFile(tracePath, `${JSON.stringify(result, null, 2)}\n`, "utf8");
|
|
60
|
+
}
|
|
61
|
+
return { reportPath, tracePath, overallScore: result.overallScore };
|
|
62
|
+
}
|
|
63
|
+
export async function evolvePolicyArtifact(cwd, focusTopic) {
|
|
64
|
+
await ensureProjectScaffold(cwd);
|
|
65
|
+
const config = await loadKeatingConfig(cwd);
|
|
66
|
+
const policyPath = currentPolicyPath(cwd);
|
|
67
|
+
const basePolicy = await loadPolicy(policyPath);
|
|
68
|
+
const meRun = await mapElitesEvolve(cwd, basePolicy, { focusTopic });
|
|
69
|
+
const run = mapElitesToEvolutionRun(meRun);
|
|
70
|
+
await savePolicy(policyPath, run.best.policy);
|
|
71
|
+
const fileName = focusTopic ? `${slugify(focusTopic)}.md` : "latest.md";
|
|
72
|
+
const reportPath = join(evolutionDir(cwd), fileName);
|
|
73
|
+
await writeFile(reportPath, mapElitesToMarkdown(meRun), "utf8");
|
|
74
|
+
const tracePath = config.debug.persistTraces
|
|
75
|
+
? join(tracesDir(cwd), `${focusTopic ? slugify(focusTopic) : "latest"}-evolution.json`)
|
|
76
|
+
: null;
|
|
77
|
+
if (tracePath) {
|
|
78
|
+
await writeFile(tracePath, `${JSON.stringify(run, null, 2)}\n`, "utf8");
|
|
79
|
+
}
|
|
80
|
+
return { reportPath, tracePath, bestScore: run.best.overallScore, policyPath };
|
|
81
|
+
}
|
|
82
|
+
export async function evolvePromptArtifact(cwd, promptName = "learn") {
|
|
83
|
+
await ensureProjectScaffold(cwd);
|
|
84
|
+
return writePromptEvolutionArtifacts(cwd, promptName);
|
|
85
|
+
}
|
|
86
|
+
export async function verifyTopicArtifact(cwd, topicName, useLLM = true) {
|
|
87
|
+
await ensureProjectScaffold(cwd);
|
|
88
|
+
const topic = resolveTopic(topicName);
|
|
89
|
+
const cachePath = verificationCachePath(cwd);
|
|
90
|
+
const cache = await loadVerificationCache(cachePath);
|
|
91
|
+
const existing = verificationStatus(topic, cache);
|
|
92
|
+
if (existing && existing.claims.every((c) => c.status !== "unconfirmed")) {
|
|
93
|
+
return {
|
|
94
|
+
checklistPath: join(verificationsDir(cwd), `${topic.slug}.md`),
|
|
95
|
+
alreadyVerified: true,
|
|
96
|
+
result: existing
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
let result;
|
|
100
|
+
if (useLLM) {
|
|
101
|
+
try {
|
|
102
|
+
result = await runCoveVerification(cwd, topic);
|
|
103
|
+
cache[topic.slug] = result;
|
|
104
|
+
await saveVerificationCache(cachePath, cache);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
console.warn(`CoVe verification failed for ${topic.slug}, falling back to manual checklist:`, error);
|
|
108
|
+
result = buildPendingVerificationResult(topic);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
result = buildPendingVerificationResult(topic);
|
|
113
|
+
}
|
|
114
|
+
const checklist = buildVerificationChecklist(topic, result);
|
|
115
|
+
const checklistPath = join(verificationsDir(cwd), `${topic.slug}.md`);
|
|
116
|
+
await writeFile(checklistPath, checklist, "utf8");
|
|
117
|
+
return { checklistPath, alreadyVerified: false, result };
|
|
118
|
+
}
|
|
119
|
+
export async function improveArtifact(cwd) {
|
|
120
|
+
await ensureProjectScaffold(cwd);
|
|
121
|
+
return generateImprovementArtifact(cwd);
|
|
122
|
+
}
|
|
123
|
+
export async function improveAccept(cwd, proposalId) {
|
|
124
|
+
await ensureProjectScaffold(cwd);
|
|
125
|
+
const evaluation = await evaluateImprovement(cwd, 0);
|
|
126
|
+
await acceptImprovement(cwd, proposalId, evaluation.afterScore);
|
|
127
|
+
return { afterScore: evaluation.afterScore, delta: evaluation.delta };
|
|
128
|
+
}
|
|
129
|
+
export async function improveReject(cwd, proposalId, snapshots) {
|
|
130
|
+
await ensureProjectScaffold(cwd);
|
|
131
|
+
await rejectImprovement(cwd, proposalId, snapshots);
|
|
132
|
+
}
|
|
133
|
+
export async function improveHistory(cwd) {
|
|
134
|
+
await ensureProjectScaffold(cwd);
|
|
135
|
+
const archive = await loadImprovementArchive(cwd);
|
|
136
|
+
return improvementHistoryToMarkdown(archive);
|
|
137
|
+
}
|
|
138
|
+
export async function autoImproveArtifact(cwd, focusTopic) {
|
|
139
|
+
await ensureProjectScaffold(cwd);
|
|
140
|
+
const baseline = await benchPolicyArtifact(cwd, focusTopic);
|
|
141
|
+
const evolved = await evolvePolicyArtifact(cwd, focusTopic);
|
|
142
|
+
const promptEvo = await evolvePromptArtifact(cwd, "learn");
|
|
143
|
+
const after = await benchPolicyArtifact(cwd, focusTopic);
|
|
144
|
+
const delta = after.overallScore - baseline.overallScore;
|
|
145
|
+
const report = [
|
|
146
|
+
`# Auto-Improve Report`,
|
|
147
|
+
``,
|
|
148
|
+
`**Baseline:** ${baseline.overallScore.toFixed(2)}/100`,
|
|
149
|
+
`**After:** ${after.overallScore.toFixed(2)}/100`,
|
|
150
|
+
`**Delta:** ${delta >= 0 ? "+" : ""}${delta.toFixed(2)}`,
|
|
151
|
+
`**Verdict:** ${delta > 0 ? "IMPROVED" : delta < -0.5 ? "REGRESSED" : "NO SIGNIFICANT CHANGE"}`,
|
|
152
|
+
``,
|
|
153
|
+
`## Benchmark`,
|
|
154
|
+
`- Report: ${relative(cwd, baseline.reportPath)}`,
|
|
155
|
+
``,
|
|
156
|
+
`## Policy Evolution`,
|
|
157
|
+
`- Best: ${evolved.bestScore.toFixed(2)}/100`,
|
|
158
|
+
`- Report: ${relative(cwd, evolved.reportPath)}`,
|
|
159
|
+
``,
|
|
160
|
+
`## Prompt Evolution`,
|
|
161
|
+
`- Best: ${promptEvo.bestScore.toFixed(2)}/100`,
|
|
162
|
+
`- Report: ${relative(cwd, promptEvo.reportPath)}`,
|
|
163
|
+
``,
|
|
164
|
+
].join("\n");
|
|
165
|
+
const reportPath = join(benchmarksDir(cwd), focusTopic ? `${slugify(focusTopic)}-auto-improve.md` : "auto-improve.md");
|
|
166
|
+
await writeFile(reportPath, report, "utf8");
|
|
167
|
+
return { baselineScore: baseline.overallScore, afterScore: after.overallScore, delta, reportPath };
|
|
168
|
+
}
|
|
169
|
+
export async function promptEvalArtifact(cwd, promptContent) {
|
|
170
|
+
await ensureProjectScaffold(cwd);
|
|
171
|
+
const slug = `eval-${Date.now().toString(36)}`;
|
|
172
|
+
const tmpPath = join(promptEvolutionDir(cwd), `${slug}.md`);
|
|
173
|
+
await writeFile(tmpPath, promptContent, "utf8");
|
|
174
|
+
const result = await evaluatePromptContent(cwd, tmpPath, promptContent);
|
|
175
|
+
const lines = [
|
|
176
|
+
`# Prompt Evaluation`,
|
|
177
|
+
``,
|
|
178
|
+
`**Score:** ${result.score.toFixed(2)}/100`,
|
|
179
|
+
``,
|
|
180
|
+
`## Objectives`,
|
|
181
|
+
...Object.entries(result.objectives).map(([k, v]) => `- ${k}: ${v.toFixed(2)}`),
|
|
182
|
+
``,
|
|
183
|
+
`## Feedback`,
|
|
184
|
+
...(result.feedback.length > 0 ? result.feedback.map((f) => `- ${f}`) : ["- No major issues detected."]),
|
|
185
|
+
];
|
|
186
|
+
const reportPath = join(promptEvolutionDir(cwd), `${slug}-eval.md`);
|
|
187
|
+
await writeFile(reportPath, lines.join("\n"), "utf8");
|
|
188
|
+
return { reportPath, score: result.score, objectives: result.objectives, feedback: result.feedback };
|
|
189
|
+
}
|
|
190
|
+
export async function timelineArtifact(cwd) {
|
|
191
|
+
await ensureProjectScaffold(cwd);
|
|
192
|
+
const state = await loadLearnerState(learnerStatePath(cwd));
|
|
193
|
+
const policy = await loadEngagementPolicy(engagementPolicyPath(cwd));
|
|
194
|
+
const timeline = buildEngagementTimeline(state, policy);
|
|
195
|
+
const markdown = engagementTimelineToMarkdown(timeline);
|
|
196
|
+
const reportPath = join(timelineDir(cwd), "latest.md");
|
|
197
|
+
await writeFile(reportPath, markdown, "utf8");
|
|
198
|
+
return { reportPath, markdown };
|
|
199
|
+
}
|
|
200
|
+
export async function dueTopicsArtifact(cwd) {
|
|
201
|
+
await ensureProjectScaffold(cwd);
|
|
202
|
+
const state = await loadLearnerState(learnerStatePath(cwd));
|
|
203
|
+
const policy = await loadEngagementPolicy(engagementPolicyPath(cwd));
|
|
204
|
+
const due = dueTopics(state, policy);
|
|
205
|
+
const markdown = dueTopicsToMarkdown(due);
|
|
206
|
+
const reportPath = join(timelineDir(cwd), "due.md");
|
|
207
|
+
await writeFile(reportPath, markdown, "utf8");
|
|
208
|
+
return { reportPath, markdown, count: due.length };
|
|
209
|
+
}
|
|
210
|
+
export async function currentPolicySummary(cwd) {
|
|
211
|
+
await ensureProjectScaffold(cwd);
|
|
212
|
+
const policy = await loadPolicy(currentPolicyPath(cwd));
|
|
213
|
+
return [
|
|
214
|
+
`Policy: ${policy.name}`,
|
|
215
|
+
`analogyDensity=${policy.analogyDensity.toFixed(2)}`,
|
|
216
|
+
`socraticRatio=${policy.socraticRatio.toFixed(2)}`,
|
|
217
|
+
`formalism=${policy.formalism.toFixed(2)}`,
|
|
218
|
+
`retrievalPractice=${policy.retrievalPractice.toFixed(2)}`,
|
|
219
|
+
`exerciseCount=${policy.exerciseCount}`,
|
|
220
|
+
`diagramBias=${policy.diagramBias.toFixed(2)}`,
|
|
221
|
+
`reflectionBias=${policy.reflectionBias.toFixed(2)}`,
|
|
222
|
+
`interdisciplinaryBias=${policy.interdisciplinaryBias.toFixed(2)}`,
|
|
223
|
+
`challengeRate=${policy.challengeRate.toFixed(2)}`
|
|
224
|
+
].join("\n");
|
|
225
|
+
}
|
|
226
|
+
export async function quizTopicArtifact(cwd, topicName) {
|
|
227
|
+
await ensureProjectScaffold(cwd);
|
|
228
|
+
const quiz = generateQuiz(topicName);
|
|
229
|
+
const slug = quiz.slug;
|
|
230
|
+
const base = join(quizDir(cwd), slug);
|
|
231
|
+
await writeFile(`${base}.md`, quizToMarkdown(quiz), "utf8");
|
|
232
|
+
await writeFile(`${base}-answers.md`, quizAnswerKeyToMarkdown(quiz), "utf8");
|
|
233
|
+
return { quizPath: `${base}.md`, answersPath: `${base}-answers.md` };
|
|
234
|
+
}
|
|
235
|
+
export async function workbookTopicArtifact(cwd, topicName) {
|
|
236
|
+
await ensureProjectScaffold(cwd);
|
|
237
|
+
const wb = generateWorkbook(topicName);
|
|
238
|
+
const wbPath = join(workbooksDir(cwd), `${wb.slug}.md`);
|
|
239
|
+
await writeFile(wbPath, workbookToMarkdown(wb), "utf8");
|
|
240
|
+
return { workbookPath: wbPath };
|
|
241
|
+
}
|
|
242
|
+
export async function flashcardsTopicArtifact(cwd, topicName) {
|
|
243
|
+
await ensureProjectScaffold(cwd);
|
|
244
|
+
const deck = generateFlashCards(topicName);
|
|
245
|
+
const deckPath = join(flashcardsDir(cwd), `${deck.slug}.md`);
|
|
246
|
+
await writeFile(deckPath, flashcardsToMarkdown(deck), "utf8");
|
|
247
|
+
return { flashcardsPath: deckPath };
|
|
248
|
+
}
|
|
249
|
+
export async function projectTopicArtifact(cwd, topicName) {
|
|
250
|
+
await ensureProjectScaffold(cwd);
|
|
251
|
+
const project = generateProject(topicName);
|
|
252
|
+
const projectPath = join(projectsDir(cwd), `${project.slug}.md`);
|
|
253
|
+
await writeFile(projectPath, projectToMarkdown(project), "utf8");
|
|
254
|
+
return { projectPath };
|
|
255
|
+
}
|
|
256
|
+
export async function assignmentTopicArtifact(cwd, topicName) {
|
|
257
|
+
await ensureProjectScaffold(cwd);
|
|
258
|
+
const assignment = generateAssignment(topicName);
|
|
259
|
+
const assignmentPath = join(projectsDir(cwd), `${assignment.slug}-assignment.md`);
|
|
260
|
+
await writeFile(assignmentPath, assignmentToMarkdown(assignment), "utf8");
|
|
261
|
+
return { assignmentPath };
|
|
262
|
+
}
|
|
263
|
+
export async function masteryTopicArtifact(cwd, topicName) {
|
|
264
|
+
await ensureProjectScaffold(cwd);
|
|
265
|
+
const topic = resolveTopic(topicName);
|
|
266
|
+
const questions = generateDiagnosticQuestions(topic);
|
|
267
|
+
const slug = topic.slug;
|
|
268
|
+
const diagPath = join(masteryDir(cwd), `${slug}-diagnostic.md`);
|
|
269
|
+
const lines = [
|
|
270
|
+
`# Diagnostic Questions: ${topic.title}`,
|
|
271
|
+
"",
|
|
272
|
+
`> Answer each question in your own words. Self-score using the rubric, or run \`keating assess ${topicName}\` after answering.`,
|
|
273
|
+
"",
|
|
274
|
+
];
|
|
275
|
+
for (const q of questions) {
|
|
276
|
+
lines.push(`## ${q.id} [${q.level}]`);
|
|
277
|
+
lines.push(q.question);
|
|
278
|
+
lines.push("");
|
|
279
|
+
lines.push(`**Rubric:** ${q.rubric}`);
|
|
280
|
+
lines.push("");
|
|
281
|
+
lines.push(`**Your answer:**`);
|
|
282
|
+
lines.push("");
|
|
283
|
+
lines.push("---");
|
|
284
|
+
lines.push("");
|
|
285
|
+
}
|
|
286
|
+
await writeFile(diagPath, lines.join("\n"), "utf8");
|
|
287
|
+
return { diagPath };
|
|
288
|
+
}
|
|
289
|
+
export async function listArtifacts(cwd) {
|
|
290
|
+
await ensureProjectScaffold(cwd);
|
|
291
|
+
const roots = [
|
|
292
|
+
plansDir(cwd),
|
|
293
|
+
mapsDir(cwd),
|
|
294
|
+
animationsDir(cwd),
|
|
295
|
+
benchmarksDir(cwd),
|
|
296
|
+
evolutionDir(cwd),
|
|
297
|
+
promptEvolutionDir(cwd),
|
|
298
|
+
tracesDir(cwd),
|
|
299
|
+
verificationsDir(cwd),
|
|
300
|
+
timelineDir(cwd),
|
|
301
|
+
quizDir(cwd),
|
|
302
|
+
flashcardsDir(cwd),
|
|
303
|
+
projectsDir(cwd),
|
|
304
|
+
workbooksDir(cwd),
|
|
305
|
+
masteryDir(cwd)
|
|
306
|
+
];
|
|
307
|
+
const artifacts = [];
|
|
308
|
+
async function collectFiles(root) {
|
|
309
|
+
const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
|
|
310
|
+
const files = [];
|
|
311
|
+
for (const entry of entries) {
|
|
312
|
+
if (entry.name === "_vendor")
|
|
313
|
+
continue;
|
|
314
|
+
const fullPath = join(root, entry.name);
|
|
315
|
+
if (entry.isDirectory()) {
|
|
316
|
+
files.push(...(await collectFiles(fullPath)));
|
|
317
|
+
}
|
|
318
|
+
else if (entry.isFile()) {
|
|
319
|
+
files.push(fullPath);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return files;
|
|
323
|
+
}
|
|
324
|
+
for (const root of roots) {
|
|
325
|
+
for (const fullPath of await collectFiles(root)) {
|
|
326
|
+
const info = await stat(fullPath);
|
|
327
|
+
artifacts.push({
|
|
328
|
+
label: `${relative(cwd, fullPath)} (${Math.round(info.size / 1024) || 1}KB)`,
|
|
329
|
+
path: relative(cwd, fullPath),
|
|
330
|
+
mtime: info.mtimeMs
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return artifacts
|
|
335
|
+
.sort((left, right) => right.mtime - left.mtime)
|
|
336
|
+
.map((artifact) => ({ label: artifact.label, path: artifact.path }));
|
|
337
|
+
}
|