@flashlearnai/cli 0.1.0 → 0.2.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--n-0:#ffffff;--n-2:#faf9f8;--n-4:#f4f3f1;--line:#e4e4e8;--line-2:#eeeef2;--sep:#c9ccd4;--ink:#1b1a19;--ink-2:#3b3a39;--muted:#5f5e5c;--faint:#8a8886;--teams:#5b5fc7;--teams-soft:#edecfa;--forest:#0e2417;--emerald:#12965a;--emerald-2:#0c7a48;--mint:#8ff0bd;--azure:#3f63d6;--azure-2:#2b46a0;--grad-dark:linear-gradient(140deg,var(--forest),#132a55);--emerald-soft:#e7f5ec;--emerald-line:#c9e8d6;--ok:#12965a;--ok-soft:#e7f5ec;--bad:#c4314b;--bad-soft:#fdeef1;--avail:#3aa657;--busy:#c50f1f;--away:#f2b73d;--sans:"Segoe UI",system-ui,-apple-system,Roboto,sans-serif;--serif:"Segoe UI",system-ui,-apple-system,Roboto,sans-serif;--mono:ui-monospace,"Cascadia Code",SFMono-Regular,Menlo,monospace;--rk:9px 3px 9px 3px;--ease:cubic-bezier(.22,.8,.28,1);--spring:cubic-bezier(.34,1.42,.5,1);--sh-1:0 1px 2px rgba(0,0,0,.05);--sh-2:0 10px 26px -14px rgba(14,36,23,.32)}*{box-sizing:border-box}html,body,#root{height:100%}body{margin:0;font-family:var(--sans);color:var(--ink);background:radial-gradient(140% 120% at 50% -8%,#dfe1ec,#bfc2d3 55%,#adb0c3);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}img{-webkit-user-drag:none;-webkit-user-select:none;user-select:none}::selection{background:var(--emerald-soft)}.stage{height:100vh;display:grid;place-items:center;padding:26px}.window{width:min(1320px,100%);height:min(816px,calc(100vh - 52px));display:flex;background:var(--n-0);border-radius:16px;overflow:hidden;box-shadow:0 0 0 1px #1820360f,0 2px 6px #18203614,0 36px 70px -30px #0c162899}.rail{width:68px;background:var(--n-2);border-right:1px solid var(--sep);display:flex;flex-direction:column;align-items:stretch;padding-top:8px;gap:2px}.rail-item{display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 0;color:var(--muted);font-size:9.5px;position:relative;transition:color .15s}.rail-item:hover{color:var(--ink)}.rail-item.on{color:var(--teams)}.rail-item.on:before{content:"";position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:var(--teams)}.rail-me{margin-top:auto;margin-bottom:12px;display:grid;place-items:center}.list{width:296px;background:var(--n-0);border-right:1px solid var(--sep);display:flex;flex-direction:column;flex-shrink:0}.list-top{padding:14px 16px 6px;display:flex;align-items:center;justify-content:space-between}.list-top h1{font-size:19px;font-weight:700;margin:0;letter-spacing:-.3px}.list-top .tools{display:flex;gap:12px;color:var(--muted)}.search{margin:2px 12px 8px;background:var(--n-4);border-radius:8px;padding:8px 11px;display:flex;align-items:center;gap:8px;color:var(--faint);font-size:12.5px}.tabs{display:flex;gap:16px;padding:2px 16px 8px;font-size:12.5px;color:var(--muted)}.tabs .on{color:var(--ink);font-weight:600;border-bottom:2px solid var(--teams);padding-bottom:6px}.chat{display:flex;gap:11px;align-items:center;padding:9px 12px;margin:0 6px;border-radius:8px;transition:background .15s}.chat:hover{background:var(--n-4)}.chat.on{background:var(--teams-soft)}.chat .meta{flex:1;min-width:0}.chat .row1{display:flex;justify-content:space-between;align-items:baseline;gap:8px}.chat .name{font-weight:600;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.chat.on .name{color:var(--teams)}.chat .time{font-size:11px;color:var(--faint);flex-shrink:0}.chat .prev{font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.chat .prev .you{color:var(--faint)}.chat.unread .prev{color:var(--ink);font-weight:600}.chat.unread .pip{width:7px;height:7px;border-radius:50%;background:var(--teams);flex-shrink:0}.avatar{border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;flex-shrink:0;position:relative;overflow:visible}.avatar .dot{position:absolute;right:-1px;bottom:-1px;width:11px;height:11px;border-radius:50%;border:2px solid #fff}.avatar.bot{background:var(--grad-dark)}.avatar.bot img{border-radius:50%}.conv{flex:1;display:flex;flex-direction:column;min-width:0;background:var(--n-0)}.conv-head{height:58px;border-bottom:1px solid var(--sep);padding:0 18px;display:flex;align-items:center;gap:11px}.conv-head .who{display:flex;flex-direction:column;gap:1px}.conv-head .title-row{display:flex;align-items:center;gap:7px}.conv-head .title{font-weight:700;font-size:15px}.conv-head .sub{font-size:11.5px;color:var(--muted);display:flex;align-items:center;gap:6px}.conv-head .sub .p{width:8px;height:8px;border-radius:50%;background:var(--avail);box-shadow:0 0 0 2px #3aa6572e}.badge{font-size:9px;font-weight:700;color:var(--emerald-2);background:var(--emerald-soft);border:1px solid var(--emerald-line);padding:1px 5px;border-radius:4px;letter-spacing:.4px}.conv-head .actions{margin-left:auto;display:flex;gap:18px;color:var(--muted)}.conv-head .actions svg{transition:color .15s}.conv-head .actions svg:hover{color:var(--ink)}.conv-tabs{height:42px;border-bottom:1px solid var(--sep);padding:0 18px;display:flex;gap:22px;align-items:center;font-size:13px;color:var(--muted)}.conv-tabs .on{color:var(--ink);font-weight:600;height:100%;display:flex;align-items:center;border-bottom:2px solid var(--teams)}.messages{flex:1;overflow-y:auto;padding:22px max(24px,calc((100% - 880px)/2)) 8px;display:flex;flex-direction:column;gap:16px;background:#f4f6f9;scroll-behavior:smooth}.divider{align-self:stretch;display:flex;align-items:center;gap:14px;color:var(--muted);font-size:12px;font-weight:500;margin:2px}.divider:before,.divider:after{content:"";height:1px;background:var(--sep);flex:1}.composer{margin:10px auto 16px;width:min(880px,calc(100% - 36px));border:1px solid var(--line);border-radius:12px;background:#fff;box-shadow:var(--sh-1)}.composer .field{padding:11px 14px;color:var(--faint);font-size:13px}.composer .bar{border-top:1px solid var(--line-2);padding:6px 12px;display:flex;align-items:center;gap:15px;color:var(--muted)}.composer .bar .send{margin-left:auto;color:var(--emerald)}.composer .bar .aa{font-weight:700;font-size:13px}.composer .bar .gif{font-size:11px;font-weight:800;letter-spacing:.5px}.msg{display:flex;gap:11px;animation:rise .5s var(--ease) both}.msg .who{width:32px;height:32px;flex-shrink:0}.msg .body{min-width:0;flex:1}.msg .head{font-size:11.5px;margin-bottom:5px;color:var(--muted)}.msg .head b{color:var(--ink)}.bubble{background:#fff;border:1px solid var(--line-2);border-radius:4px 14px 14px;padding:10px 13px;font-size:13.5px;line-height:1.45;display:inline-block;max-width:80%;box-shadow:var(--sh-1)}.user-msg{align-self:flex-end;max-width:70%;display:flex;flex-direction:column;align-items:flex-end;animation:riseR .45s var(--ease) both}.user-bubble{background:var(--emerald-soft);border:1px solid var(--emerald-line);color:#0c3d25;border-radius:14px 14px 2px;padding:9px 13px;font-size:13px;font-weight:600}.typing{display:inline-flex;gap:4px;padding:12px 14px;background:#fff;border:1px solid var(--line-2);border-radius:4px 14px 14px;box-shadow:var(--sh-1)}.typing i{width:7px;height:7px;border-radius:50%;background:#c7ccc9;animation:blink 1.2s infinite}.typing i:nth-child(2){animation-delay:.2s}.typing i:nth-child(3){animation-delay:.4s}.welcome{max-width:432px;border-radius:28px 10px;overflow:hidden;border:1px solid #143122;background:radial-gradient(125% 112% at 6% 0%,#173d29,#0c2419 55%,#0e2340);color:#fff;box-shadow:var(--sh-2);position:relative;animation:cardIn .55s var(--spring) both}.welcome:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background-image:radial-gradient(circle at 1px 1px,rgba(143,240,189,.14) 1px,transparent 0);background-size:18px 18px;opacity:.5;pointer-events:none}.welcome .inner{position:relative;padding:26px 24px 24px}.welcome .mk{width:58px;height:58px;border-radius:18px 6px;overflow:hidden;background:var(--grad-dark);display:grid;place-items:center;box-shadow:0 8px 22px -8px #0009;border:1px solid #204634}.welcome h2{font-family:var(--serif);font-weight:600;font-size:27px;margin:16px 0 6px;letter-spacing:-.4px}.welcome p{color:#bfe9cf;font-size:13.5px;line-height:1.5;margin:0 0 20px;max-width:34ch}.welcome .cta{display:inline-flex;align-items:center;gap:9px;background:var(--mint);color:#0b1c12;font-weight:700;font-size:14px;padding:12px 20px;border-radius:14px 6px;transition:transform .18s var(--spring),box-shadow .18s}.welcome .cta:hover{transform:translateY(-2px);box-shadow:0 12px 26px -12px #8ff0bd99}.welcome .meta{display:flex;gap:18px;margin-top:18px;color:#8db8a1;font-size:11.5px}.welcome .meta b{color:#eafff3;font-family:var(--serif);font-size:15px}.pick{max-width:400px;border-radius:26px 8px;overflow:hidden;border:1px solid var(--line);box-shadow:var(--sh-2);background:#fff;animation:cardIn .5s var(--spring) both}.pick-head{padding:16px 18px 6px;display:flex;align-items:flex-start;justify-content:space-between}.pick-head .psub{display:block;font-size:11.5px;color:var(--faint);margin-top:3px}.pick-head .t{font-family:var(--serif);font-size:19px;font-weight:600;color:var(--forest);letter-spacing:-.3px}.selall{font-size:11px;color:var(--emerald-2);background:var(--emerald-soft);border:1px solid var(--emerald-line);border-radius:10px 4px;padding:5px 11px;font-weight:700;transition:.15s}.selall:hover{background:#d7f0e0}.pick-body{padding:12px 18px 18px}.topics{display:flex;flex-direction:column;gap:9px}.topic{display:flex;align-items:center;gap:12px;border:1.5px solid var(--line);padding:12px 13px;text-align:left;width:100%;background:#fff;transition:transform .16s var(--spring),border-color .15s,background .15s,box-shadow .16s}.topic:nth-child(odd){border-radius:16px 6px}.topic:nth-child(2n){border-radius:6px 16px}.topic:hover{border-color:var(--a);transform:translateY(-1px);box-shadow:0 12px 24px -16px color-mix(in srgb,var(--a) 75%,transparent)}.topic.sel{border-color:var(--a);background:color-mix(in srgb,var(--a) 6%,#fff)}.tglyph{width:36px;height:36px;border-radius:11px 4px;display:grid;place-items:center;color:var(--a);background:color-mix(in srgb,var(--a) 13%,#fff);flex-shrink:0;transition:.16s}.topic.sel .tglyph{background:var(--a);color:#fff}.tmain{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.tlabel{font-weight:600;font-size:14px;color:var(--ink)}.tmastery{display:flex;align-items:center;gap:8px}.tmastery em{font-style:normal;font-size:10.5px;color:var(--faint)}.tcheck{width:24px;height:24px;border-radius:50%;border:1.6px solid #cdd3cd;display:grid;place-items:center;color:#fff;flex-shrink:0;transition:.16s}.topic.sel .tcheck{background:var(--a);border-color:var(--a);animation:pop .3s var(--spring)}.lone{margin:0 0 4px;font-size:15px;line-height:1.5;color:var(--ink);background:var(--emerald-soft);border:1px solid var(--emerald-line);border-radius:12px 4px;padding:12px 14px}.welcome .cmd{margin:14px 0 0;font-family:var(--mono);font-size:12.5px;color:var(--mint);background:#00000047;border:1px solid rgba(143,240,189,.22);border-radius:8px 3px;padding:9px 12px;display:inline-block}.capped{margin:9px 2px 0;font-size:11px;line-height:1.5;color:var(--faint);text-align:center}.start{width:100%;margin-top:15px;background:var(--grad-dark);color:#fff;border:1.5px solid transparent;border-radius:16px 6px;padding:13px;font-weight:600;font-size:14px;display:flex;align-items:center;justify-content:center;gap:8px;transition:transform .18s var(--spring),box-shadow .18s,background .2s,color .2s,border-color .2s}.start:not(:disabled):hover{transform:translateY(-2px);box-shadow:0 14px 30px -14px #1f4fb08c}.start:disabled{background:transparent;color:var(--faint);border-color:var(--line);cursor:default}.qcard{position:relative;max-width:432px;padding:20px 20px 18px;background:linear-gradient(180deg,#fff,#fcfdfb);border:1px solid var(--line);border-radius:28px 8px;box-shadow:var(--sh-2),inset 0 1px #fff;overflow:hidden;animation:cardIn .5s var(--spring) both}.qtop{position:relative;display:flex;align-items:center;justify-content:space-between}.qbrand{display:flex;align-items:center;gap:8px;font-weight:600;font-size:12px;color:var(--forest)}.qbrand .m{width:22px;height:22px;border-radius:8px 3px;overflow:hidden;background:var(--grad-dark);display:grid;place-items:center}.qmeta{position:relative;display:flex;align-items:center;gap:11px;margin:15px 0 3px}.qmeta .frac{font-family:var(--mono);font-size:11px;color:var(--faint);letter-spacing:.5px;flex-shrink:0}.qseg{flex:1;display:flex;gap:3px}.qseg>i{flex:1;height:5px;border-radius:2px;background:#e6ebe6;transition:background .4s}.qseg>i.done{background:var(--emerald)}.qseg>i.cur{background:var(--azure)}.qtext{position:relative;font-family:var(--serif);font-weight:700;font-size:22px;line-height:1.24;color:var(--forest);letter-spacing:-.4px;margin:12px 0 16px}.qchoices{position:relative;display:flex;flex-direction:column;gap:9px}.qchoice{display:flex;align-items:center;gap:13px;padding:13px 15px;border:1.5px solid var(--line);background:#fff;text-align:left;width:100%;font-size:14.5px;color:var(--ink);transition:transform .18s var(--spring),border-color .16s,box-shadow .16s,background .16s;animation:choiceIn .42s var(--spring) both}.qc-text{flex:1}.qc-mark{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;color:#fff;flex-shrink:0;animation:pop .3s var(--spring)}.qc-mark.ok{background:var(--ok)}.qc-mark.no{background:var(--bad)}.qchoice:nth-child(odd){border-radius:16px 6px}.qchoice:nth-child(2n){border-radius:6px 16px}.qchoice:nth-child(1){animation-delay:.06s}.qchoice:nth-child(2){animation-delay:.13s}.qchoice:nth-child(3){animation-delay:.2s}.qchoice:nth-child(4){animation-delay:.27s}.qchoice:not(:disabled):hover{border-color:var(--emerald);transform:translateY(-2px);box-shadow:0 12px 24px -14px #12965a99}.qchoice:disabled{cursor:default}.qchoice .k{width:27px;height:27px;border-radius:var(--rk);background:var(--n-4);color:var(--emerald-2);font-weight:800;font-size:12px;display:grid;place-items:center;flex-shrink:0;border:1px solid var(--line);transition:.16s}.qchoice:not(:disabled):hover .k{background:var(--forest);color:var(--mint)}.qchoice.correct{border-color:var(--ok);background:var(--ok-soft);font-weight:600}.qchoice.correct .k{background:var(--ok);color:#fff;animation:pop .34s var(--spring)}.qchoice.wrong{border-color:var(--bad);background:var(--bad-soft);font-weight:600}.qchoice.wrong .k{background:var(--bad);color:#fff}.qchoice.dim{opacity:.4}.confused{margin:14px 0 0;font-size:12.5px;line-height:1.55;color:var(--muted)}.confused b{color:var(--ink)}.qsrc{position:relative;display:flex;align-items:center;gap:7px;width:100%;font-size:10.5px;color:var(--faint);margin:16px 0 0;padding:12px 0 0;border-top:1px dashed var(--line);font-family:var(--mono);background:none;text-align:left;transition:color .15s}.qsrc:hover{color:var(--muted)}.qsrc .chev{margin-left:auto;transition:transform .22s var(--ease)}.qsrc.open .chev{transform:rotate(180deg)}.qcode{margin-top:11px;border-radius:12px 4px;overflow:hidden;border:1px solid #17301f;box-shadow:0 12px 26px -18px #0e2417a6;animation:codeIn .3s var(--ease) both}.qcode-h{background:#0b1c12;color:#9cc7b0;padding:8px 12px;font-family:var(--mono);font-size:10px;display:flex;align-items:center;gap:7px;border-bottom:1px solid #17301f;letter-spacing:.2px}.qcode-h .g{color:var(--mint)}.qcode pre{margin:0;padding:12px 14px;background:#0e2417;color:#cfe9db;font-family:var(--mono);font-size:11.5px;line-height:1.6;white-space:pre-wrap;word-break:break-word}@keyframes codeIn{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}.qsrc .sha{color:var(--emerald-2);background:var(--emerald-soft);border-radius:5px;padding:1px 6px}.grade{margin-top:15px}.grade-q{font-size:11.5px;color:var(--muted);font-weight:600;letter-spacing:.2px;margin-bottom:9px}.grade-btns{display:grid;grid-template-columns:1fr 1fr;gap:7px}.g-primary{width:100%;margin-top:8px;display:flex;align-items:center;justify-content:center;gap:8px;padding:12px;border:none;border-radius:14px 6px;background:var(--grad-dark);color:#fff;font-weight:600;font-size:13.5px;transition:transform .15s var(--spring),box-shadow .18s}.g-primary:hover{transform:translateY(-1px);box-shadow:0 12px 26px -14px #122a5280}.g{display:flex;flex-direction:column;align-items:center;gap:3px;padding:10px 4px;border:1.5px solid var(--line);border-radius:12px 4px;font-size:12.5px;font-weight:700;background:#fff;color:var(--ink);transition:transform .15s var(--spring),border-color .15s,box-shadow .15s,background .15s}.g em{font-style:normal;font-size:9.5px;color:var(--faint);font-weight:600}.g:hover{transform:translateY(-2px);box-shadow:var(--sh-1)}.g-hard:hover{border-color:#c78a1f;background:#fdf3e1;color:#a3701a}.g-easy:hover{border-color:var(--azure);background:#eef2fd;color:var(--azure-2)}.graded{margin-top:13px;font-size:12px;color:var(--muted)}.graded.unrecorded{color:var(--bad)}.qtext,.lone,.qsrc{overflow-wrap:anywhere}.results{position:relative;max-width:420px;border-radius:28px 8px;overflow:hidden;border:1px solid var(--line);box-shadow:var(--sh-2);background:linear-gradient(180deg,#fff,#fbfdfb);padding:22px;text-align:left;animation:cardIn .5s var(--spring) both}.results-top{display:flex;align-items:center;gap:16px}.results .ring .val{font-family:var(--serif);font-size:26px;font-weight:700;color:var(--forest)}.results-head h3{font-family:var(--serif);font-size:19px;color:var(--forest);margin:0 0 4px}.results-head .sub{color:var(--muted);font-size:12.5px;line-height:1.5}.missed{display:flex;flex-direction:column;gap:8px}.miss{display:flex;align-items:center;gap:10px;font-size:12.5px;color:var(--ink-2)}.miss .mx{width:20px;height:20px;flex-shrink:0;border-radius:50%;background:var(--bad-soft);color:var(--bad);display:grid;place-items:center}.miss .mq{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.results .again{width:100%;margin-top:18px}.confetti{position:absolute;top:0;left:0;right:0;height:0;pointer-events:none}.confetti i{position:absolute;top:0;width:8px;height:12px;border-radius:2px;opacity:0;animation:fall 1.4s var(--ease) forwards}.details{width:300px;border-left:1px solid var(--sep);background:var(--n-2);display:flex;flex-direction:column;flex-shrink:0;overflow-y:auto}.details .hero{padding:24px 20px 20px;text-align:center;border-bottom:1px solid var(--line)}.details .hero .mk{width:66px;height:66px;border-radius:20px 7px;overflow:hidden;margin:0 auto 13px;background:var(--grad-dark);display:grid;place-items:center;box-shadow:var(--sh-2)}.details .hero h3{font-family:var(--serif);font-size:20px;color:var(--forest);margin:0 0 2px}.details .hero .by{font-size:12px;color:var(--muted)}.details .hero .pill{display:inline-flex;align-items:center;gap:6px;margin-top:12px;font-size:11.5px;color:var(--emerald-2);background:var(--emerald-soft);border:1px solid var(--emerald-line);border-radius:99px;padding:4px 11px;font-weight:600}.details .hero .pill .p{width:7px;height:7px;border-radius:50%;background:var(--avail)}.dsec{padding:16px 20px;border-bottom:1px solid var(--line)}.dsec h4{font-size:10.5px;letter-spacing:1.2px;text-transform:uppercase;color:var(--faint);margin:0 0 10px;font-weight:700}.dsec p{margin:0;font-size:12.5px;line-height:1.55;color:var(--ink-2)}.steps{display:flex;flex-direction:column;gap:11px}.step{display:flex;gap:11px;align-items:flex-start;font-size:12.5px;color:var(--ink-2)}.step .n{width:22px;height:22px;flex-shrink:0;border-radius:7px 3px;background:var(--grad-dark);color:var(--mint);font-weight:700;font-size:11px;display:grid;place-items:center}.dstats{display:flex;gap:10px}.dstat{flex:1;border:1px solid var(--line);border-radius:12px 5px;padding:11px 8px;text-align:center;background:#fff}.dstat b{display:block;font-family:var(--serif);font-size:21px;color:var(--forest);line-height:1}.dstat span{font-size:10px;color:var(--faint);letter-spacing:.3px;text-transform:uppercase}.prog{display:flex;align-items:center;gap:14px;margin-bottom:14px}.ring{position:relative;flex-shrink:0;display:grid;place-items:center}.ring .rval{font-family:var(--serif);font-size:17px;color:var(--forest);letter-spacing:-.3px}.pline{margin:0;font-size:12.5px;line-height:1.5;color:var(--muted)}.pline b{color:var(--ink);font-size:14px}.runs{display:flex;flex-direction:column;gap:8px}.run{display:flex;align-items:center;gap:10px;font-size:12.5px;color:var(--ink-2)}.run .lab{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.run.now .lab{font-weight:700;color:var(--ink)}.run.next{opacity:.45}.run .sc{font-family:var(--mono);font-size:10.5px;color:var(--faint)}.run .bars{display:flex;gap:2px}.run .bars i{width:12px;height:5px;border-radius:2px;background:#e0e5e0;transition:background .3s}.run .bars i.ok{background:var(--emerald)}.run .bars i.no{background:var(--bad)}.insights{display:flex;flex-direction:column;gap:12px}.insight{display:flex;flex-direction:column;gap:5px}.insight-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;font-size:12.5px;color:var(--ink-2)}.insight-head span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.insight-head b{font-family:var(--mono);font-size:11px;color:var(--forest)}.insight-track{display:block;height:6px;border-radius:3px;background:#e1e6e2;overflow:hidden}.insight-track i{display:block;height:100%;border-radius:inherit;background:var(--emerald)}.insight small{font-size:10.5px;color:var(--faint)}@keyframes rise{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}@keyframes riseR{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}@keyframes cardIn{0%{opacity:0;transform:translateY(16px) scale(.985)}to{opacity:1;transform:none}}@keyframes choiceIn{0%{opacity:0;transform:translate(-10px)}to{opacity:1;transform:none}}@keyframes pop{0%{transform:scale(.5)}60%{transform:scale(1.18)}to{transform:scale(1)}}@keyframes blink{0%,60%,to{opacity:.3;transform:translateY(0)}30%{opacity:1;transform:translateY(-3px)}}@keyframes fall{0%{opacity:1;transform:translateY(0) rotate(0)}to{opacity:0;transform:translateY(320px) rotate(320deg)}}@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}.live-insights{display:none}@media(max-width:1120px){.details{display:none}.live-insights{display:block;background:var(--n-2);border:1px solid var(--sep);border-radius:8px;margin-bottom:16px}.live-insights summary{cursor:pointer;padding:12px 20px;color:var(--forest)}}@media(max-width:840px){.rail{display:none}.list{width:86px}.list .name,.list .prev,.list-top h1,.search,.tabs,.chat .time{display:none}.chat{justify-content:center;padding:9px 0;margin:0}.window{height:calc(100vh - 24px)}.stage{padding:12px}.messages{padding:18px 14px 8px}}
|
|
1
|
+
:root{--n-0:#ffffff;--n-2:#faf9f8;--n-4:#f4f3f1;--line:#e4e4e8;--line-2:#eeeef2;--sep:#c9ccd4;--ink:#1b1a19;--ink-2:#3b3a39;--muted:#5f5e5c;--faint:#8a8886;--teams:#5b5fc7;--teams-soft:#edecfa;--forest:#0e2417;--emerald:#12965a;--emerald-2:#0c7a48;--mint:#8ff0bd;--azure:#3f63d6;--azure-2:#2b46a0;--grad-dark:linear-gradient(140deg,var(--forest),#132a55);--emerald-soft:#e7f5ec;--emerald-line:#c9e8d6;--ok:#12965a;--ok-soft:#e7f5ec;--bad:#c4314b;--bad-soft:#fdeef1;--avail:#3aa657;--busy:#c50f1f;--away:#f2b73d;--sans:"Segoe UI",system-ui,-apple-system,Roboto,sans-serif;--serif:"Segoe UI",system-ui,-apple-system,Roboto,sans-serif;--mono:ui-monospace,"Cascadia Code",SFMono-Regular,Menlo,monospace;--rk:9px 3px 9px 3px;--ease:cubic-bezier(.22,.8,.28,1);--spring:cubic-bezier(.34,1.42,.5,1);--sh-1:0 1px 2px rgba(0,0,0,.05);--sh-2:0 10px 26px -14px rgba(14,36,23,.32)}*{box-sizing:border-box}html,body,#root{height:100%}body{margin:0;font-family:var(--sans);color:var(--ink);background:radial-gradient(140% 120% at 50% -8%,#dfe1ec,#bfc2d3 55%,#adb0c3);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}img{-webkit-user-drag:none;-webkit-user-select:none;user-select:none}::selection{background:var(--emerald-soft)}.stage{height:100vh;display:grid;place-items:center;padding:26px}.window{width:min(1320px,100%);height:min(816px,calc(100vh - 52px));display:flex;background:var(--n-0);border-radius:16px;overflow:hidden;box-shadow:0 0 0 1px #1820360f,0 2px 6px #18203614,0 36px 70px -30px #0c162899}.rail{width:68px;background:var(--n-2);border-right:1px solid var(--sep);display:flex;flex-direction:column;align-items:stretch;padding-top:8px;gap:2px}.rail-item{display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 0;color:var(--muted);font-size:9.5px;position:relative;transition:color .15s}.rail-item:hover{color:var(--ink)}.rail-item.on{color:var(--teams)}.rail-item.on:before{content:"";position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:var(--teams)}.rail-me{margin-top:auto;margin-bottom:12px;display:grid;place-items:center}.list{width:296px;background:var(--n-0);border-right:1px solid var(--sep);display:flex;flex-direction:column;flex-shrink:0}.list-top{padding:14px 16px 6px;display:flex;align-items:center;justify-content:space-between}.list-top h1{font-size:19px;font-weight:700;margin:0;letter-spacing:-.3px}.list-top .tools{display:flex;gap:12px;color:var(--muted)}.search{margin:2px 12px 8px;background:var(--n-4);border-radius:8px;padding:8px 11px;display:flex;align-items:center;gap:8px;color:var(--faint);font-size:12.5px}.tabs{display:flex;gap:16px;padding:2px 16px 8px;font-size:12.5px;color:var(--muted)}.tabs .on{color:var(--ink);font-weight:600;border-bottom:2px solid var(--teams);padding-bottom:6px}.chat{display:flex;gap:11px;align-items:center;padding:9px 12px;margin:0 6px;border-radius:8px;transition:background .15s}.chat:hover{background:var(--n-4)}.chat.on{background:var(--teams-soft)}.chat .meta{flex:1;min-width:0}.chat .row1{display:flex;justify-content:space-between;align-items:baseline;gap:8px}.chat .name{font-weight:600;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.chat.on .name{color:var(--teams)}.chat .time{font-size:11px;color:var(--faint);flex-shrink:0}.chat .prev{font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.chat .prev .you{color:var(--faint)}.chat.unread .prev{color:var(--ink);font-weight:600}.chat.unread .pip{width:7px;height:7px;border-radius:50%;background:var(--teams);flex-shrink:0}.avatar{border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;flex-shrink:0;position:relative;overflow:visible}.avatar .dot{position:absolute;right:-1px;bottom:-1px;width:11px;height:11px;border-radius:50%;border:2px solid #fff}.avatar.bot{background:var(--grad-dark)}.avatar.bot img{border-radius:50%}.conv{flex:1;display:flex;flex-direction:column;min-width:0;background:var(--n-0)}.conv-head{height:58px;border-bottom:1px solid var(--sep);padding:0 18px;display:flex;align-items:center;gap:11px}.conv-head .who{display:flex;flex-direction:column;gap:1px}.conv-head .title-row{display:flex;align-items:center;gap:7px}.conv-head .title{font-weight:700;font-size:15px}.conv-head .sub{font-size:11.5px;color:var(--muted);display:flex;align-items:center;gap:6px}.conv-head .sub .p{width:8px;height:8px;border-radius:50%;background:var(--avail);box-shadow:0 0 0 2px #3aa6572e}.badge{font-size:9px;font-weight:700;color:var(--emerald-2);background:var(--emerald-soft);border:1px solid var(--emerald-line);padding:1px 5px;border-radius:4px;letter-spacing:.4px}.conv-head .actions{margin-left:auto;display:flex;gap:18px;color:var(--muted)}.conv-head .actions svg{transition:color .15s}.conv-head .actions svg:hover{color:var(--ink)}.conv-tabs{height:42px;border-bottom:1px solid var(--sep);padding:0 18px;display:flex;gap:22px;align-items:center;font-size:13px;color:var(--muted)}.conv-tabs .on{color:var(--ink);font-weight:600;height:100%;display:flex;align-items:center;border-bottom:2px solid var(--teams)}.messages{flex:1;overflow-y:auto;padding:22px max(24px,calc((100% - 880px)/2)) 8px;display:flex;flex-direction:column;gap:16px;background:#f4f6f9;scroll-behavior:smooth}.divider{align-self:stretch;display:flex;align-items:center;gap:14px;color:var(--muted);font-size:12px;font-weight:500;margin:2px}.divider:before,.divider:after{content:"";height:1px;background:var(--sep);flex:1}.composer{margin:10px auto 16px;width:min(880px,calc(100% - 36px));border:1px solid var(--line);border-radius:12px;background:#fff;box-shadow:var(--sh-1)}.composer .field{padding:11px 14px;color:var(--faint);font-size:13px}.composer .bar{border-top:1px solid var(--line-2);padding:6px 12px;display:flex;align-items:center;gap:15px;color:var(--muted)}.composer .bar .send{margin-left:auto;color:var(--emerald)}.composer .bar .aa{font-weight:700;font-size:13px}.composer .bar .gif{font-size:11px;font-weight:800;letter-spacing:.5px}.msg{display:flex;gap:11px;animation:rise .5s var(--ease) both}.msg .who{width:32px;height:32px;flex-shrink:0}.msg .body{min-width:0;flex:1}.msg .head{font-size:11.5px;margin-bottom:5px;color:var(--muted)}.msg .head b{color:var(--ink)}.bubble{background:#fff;border:1px solid var(--line-2);border-radius:4px 14px 14px;padding:10px 13px;font-size:13.5px;line-height:1.45;display:inline-block;max-width:80%;box-shadow:var(--sh-1)}.user-msg{align-self:flex-end;max-width:70%;display:flex;flex-direction:column;align-items:flex-end;animation:riseR .45s var(--ease) both}.user-bubble{background:var(--emerald-soft);border:1px solid var(--emerald-line);color:#0c3d25;border-radius:14px 14px 2px;padding:9px 13px;font-size:13px;font-weight:600}.typing{display:inline-flex;gap:4px;padding:12px 14px;background:#fff;border:1px solid var(--line-2);border-radius:4px 14px 14px;box-shadow:var(--sh-1)}.typing i{width:7px;height:7px;border-radius:50%;background:#c7ccc9;animation:blink 1.2s infinite}.typing i:nth-child(2){animation-delay:.2s}.typing i:nth-child(3){animation-delay:.4s}.welcome{max-width:432px;border-radius:28px 10px;overflow:hidden;border:1px solid #143122;background:radial-gradient(125% 112% at 6% 0%,#173d29,#0c2419 55%,#0e2340);color:#fff;box-shadow:var(--sh-2);position:relative;animation:cardIn .55s var(--spring) both}.welcome:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background-image:radial-gradient(circle at 1px 1px,rgba(143,240,189,.14) 1px,transparent 0);background-size:18px 18px;opacity:.5;pointer-events:none}.welcome .inner{position:relative;padding:26px 24px 24px}.welcome .mk{width:58px;height:58px;border-radius:18px 6px;overflow:hidden;background:var(--grad-dark);display:grid;place-items:center;box-shadow:0 8px 22px -8px #0009;border:1px solid #204634}.welcome h2{font-family:var(--serif);font-weight:600;font-size:27px;margin:16px 0 6px;letter-spacing:-.4px}.welcome p{color:#bfe9cf;font-size:13.5px;line-height:1.5;margin:0 0 20px;max-width:34ch}.welcome .cta{display:inline-flex;align-items:center;gap:9px;background:var(--mint);color:#0b1c12;font-weight:700;font-size:14px;padding:12px 20px;border-radius:14px 6px;transition:transform .18s var(--spring),box-shadow .18s}.welcome .cta:hover{transform:translateY(-2px);box-shadow:0 12px 26px -12px #8ff0bd99}.welcome .meta{display:flex;gap:18px;margin-top:18px;color:#8db8a1;font-size:11.5px}.welcome .meta b{color:#eafff3;font-family:var(--serif);font-size:15px}.pick{max-width:400px;border-radius:26px 8px;overflow:hidden;border:1px solid var(--line);box-shadow:var(--sh-2);background:#fff;animation:cardIn .5s var(--spring) both}.pick-head{padding:16px 18px 6px;display:flex;align-items:flex-start;justify-content:space-between}.pick-head .psub{display:block;font-size:11.5px;color:var(--faint);margin-top:3px}.pick-head .t{font-family:var(--serif);font-size:19px;font-weight:600;color:var(--forest);letter-spacing:-.3px}.selall{font-size:11px;color:var(--emerald-2);background:var(--emerald-soft);border:1px solid var(--emerald-line);border-radius:10px 4px;padding:5px 11px;font-weight:700;transition:.15s}.selall:hover{background:#d7f0e0}.pick-body{padding:12px 18px 18px}.topics{display:flex;flex-direction:column;gap:9px}.topic{display:flex;align-items:center;gap:12px;border:1.5px solid var(--line);padding:12px 13px;text-align:left;width:100%;background:#fff;transition:transform .16s var(--spring),border-color .15s,background .15s,box-shadow .16s}.topic:nth-child(odd){border-radius:16px 6px}.topic:nth-child(2n){border-radius:6px 16px}.topic:hover{border-color:var(--a);transform:translateY(-1px);box-shadow:0 12px 24px -16px color-mix(in srgb,var(--a) 75%,transparent)}.topic.sel{border-color:var(--a);background:color-mix(in srgb,var(--a) 6%,#fff)}.tglyph{width:36px;height:36px;border-radius:11px 4px;display:grid;place-items:center;color:var(--a);background:color-mix(in srgb,var(--a) 13%,#fff);flex-shrink:0;transition:.16s}.topic.sel .tglyph{background:var(--a);color:#fff}.tmain{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.tlabel{font-weight:600;font-size:14px;color:var(--ink)}.tmastery{display:flex;align-items:center;gap:8px}.tmastery em{font-style:normal;font-size:10.5px;color:var(--faint)}.tcheck{width:24px;height:24px;border-radius:50%;border:1.6px solid #cdd3cd;display:grid;place-items:center;color:#fff;flex-shrink:0;transition:.16s}.topic.sel .tcheck{background:var(--a);border-color:var(--a);animation:pop .3s var(--spring)}.lone{margin:0 0 4px;font-size:15px;line-height:1.5;color:var(--ink);background:var(--emerald-soft);border:1px solid var(--emerald-line);border-radius:12px 4px;padding:12px 14px}.welcome .cmd{margin:14px 0 0;font-family:var(--mono);font-size:12.5px;color:var(--mint);background:#00000047;border:1px solid rgba(143,240,189,.22);border-radius:8px 3px;padding:9px 12px;display:inline-block}.capped{margin:9px 2px 0;font-size:11px;line-height:1.5;color:var(--faint);text-align:center}.start{width:100%;margin-top:15px;background:var(--grad-dark);color:#fff;border:1.5px solid transparent;border-radius:16px 6px;padding:13px;font-weight:600;font-size:14px;display:flex;align-items:center;justify-content:center;gap:8px;transition:transform .18s var(--spring),box-shadow .18s,background .2s,color .2s,border-color .2s}.start:not(:disabled):hover{transform:translateY(-2px);box-shadow:0 14px 30px -14px #1f4fb08c}.start:disabled{background:transparent;color:var(--faint);border-color:var(--line);cursor:default}.qcard{position:relative;max-width:432px;padding:20px 20px 18px;background:linear-gradient(180deg,#fff,#fcfdfb);border:1px solid var(--line);border-radius:28px 8px;box-shadow:var(--sh-2),inset 0 1px #fff;overflow:hidden;animation:cardIn .5s var(--spring) both}.qtop{position:relative;display:flex;align-items:center;justify-content:space-between}.qbrand{display:flex;align-items:center;gap:8px;font-weight:600;font-size:12px;color:var(--forest)}.qbrand .m{width:22px;height:22px;border-radius:8px 3px;overflow:hidden;background:var(--grad-dark);display:grid;place-items:center}.qmeta{position:relative;display:flex;align-items:center;gap:11px;margin:15px 0 3px}.qmeta .frac{font-family:var(--mono);font-size:11px;color:var(--faint);letter-spacing:.5px;flex-shrink:0}.qseg{flex:1;display:flex;gap:3px}.qseg>i{flex:1;height:5px;border-radius:2px;background:#e6ebe6;transition:background .4s}.qseg>i.done{background:var(--emerald)}.qseg>i.cur{background:var(--azure)}.qtext{position:relative;font-family:var(--serif);font-weight:700;font-size:22px;line-height:1.24;color:var(--forest);letter-spacing:-.4px;margin:12px 0 16px}.qchoices{position:relative;display:flex;flex-direction:column;gap:9px}.qchoice{display:flex;align-items:center;gap:13px;padding:13px 15px;border:1.5px solid var(--line);background:#fff;text-align:left;width:100%;font-size:14.5px;color:var(--ink);transition:transform .18s var(--spring),border-color .16s,box-shadow .16s,background .16s;animation:choiceIn .42s var(--spring) both}.qc-text{flex:1}.qc-mark{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;color:#fff;flex-shrink:0;animation:pop .3s var(--spring)}.qc-mark.ok{background:var(--ok)}.qc-mark.no{background:var(--bad)}.qchoice:nth-child(odd){border-radius:16px 6px}.qchoice:nth-child(2n){border-radius:6px 16px}.qchoice:nth-child(1){animation-delay:.06s}.qchoice:nth-child(2){animation-delay:.13s}.qchoice:nth-child(3){animation-delay:.2s}.qchoice:nth-child(4){animation-delay:.27s}.qchoice:not(:disabled):hover{border-color:var(--emerald);transform:translateY(-2px);box-shadow:0 12px 24px -14px #12965a99}.qchoice:disabled{cursor:default}.qchoice .k{width:27px;height:27px;border-radius:var(--rk);background:var(--n-4);color:var(--emerald-2);font-weight:800;font-size:12px;display:grid;place-items:center;flex-shrink:0;border:1px solid var(--line);transition:.16s}.qchoice:not(:disabled):hover .k{background:var(--forest);color:var(--mint)}.qchoice.correct{border-color:var(--ok);background:var(--ok-soft);font-weight:600}.qchoice.correct .k{background:var(--ok);color:#fff;animation:pop .34s var(--spring)}.qchoice.wrong{border-color:var(--bad);background:var(--bad-soft);font-weight:600}.qchoice.wrong .k{background:var(--bad);color:#fff}.qchoice.dim{opacity:.4}.confused{margin:14px 0 0;font-size:12.5px;line-height:1.55;color:var(--muted)}.confused b{color:var(--ink)}.qsrc{position:relative;display:flex;align-items:center;gap:7px;width:100%;font-size:10.5px;color:var(--faint);margin:16px 0 0;padding:12px 0 0;border-top:1px dashed var(--line);font-family:var(--mono);background:none;text-align:left;transition:color .15s}button.qsrc:hover{color:var(--muted)}.qsrc .chev{margin-left:auto;transition:transform .22s var(--ease)}.qsrc.open .chev{transform:rotate(180deg)}.qcode{margin-top:11px;border-radius:12px 4px;overflow:hidden;border:1px solid #17301f;box-shadow:0 12px 26px -18px #0e2417a6;animation:codeIn .3s var(--ease) both}.qcode-h{background:#0b1c12;color:#9cc7b0;padding:8px 12px;font-family:var(--mono);font-size:10px;display:flex;align-items:center;gap:7px;border-bottom:1px solid #17301f;letter-spacing:.2px}.qcode-h .g{color:var(--mint)}.qcode pre{margin:0;padding:12px 14px;background:#0e2417;color:#cfe9db;font-family:var(--mono);font-size:11.5px;line-height:1.6;white-space:pre-wrap;word-break:break-word}@keyframes codeIn{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}.qsrc .sha{color:var(--emerald-2);background:var(--emerald-soft);border-radius:5px;padding:1px 6px}.grade{margin-top:15px}.grade-q{font-size:11.5px;color:var(--muted);font-weight:600;letter-spacing:.2px;margin-bottom:9px}.grade-btns{display:grid;grid-template-columns:1fr 1fr;gap:7px}.g-primary{width:100%;margin-top:8px;display:flex;align-items:center;justify-content:center;gap:8px;padding:12px;border:none;border-radius:14px 6px;background:var(--grad-dark);color:#fff;font-weight:600;font-size:13.5px;transition:transform .15s var(--spring),box-shadow .18s}.g-primary:hover{transform:translateY(-1px);box-shadow:0 12px 26px -14px #122a5280}.g{display:flex;flex-direction:column;align-items:center;gap:3px;padding:10px 4px;border:1.5px solid var(--line);border-radius:12px 4px;font-size:12.5px;font-weight:700;background:#fff;color:var(--ink);transition:transform .15s var(--spring),border-color .15s,box-shadow .15s,background .15s}.g em{font-style:normal;font-size:9.5px;color:var(--faint);font-weight:600}.g:hover{transform:translateY(-2px);box-shadow:var(--sh-1)}.g-hard:hover{border-color:#c78a1f;background:#fdf3e1;color:#a3701a}.g-easy:hover{border-color:var(--azure);background:#eef2fd;color:var(--azure-2)}.graded{margin-top:13px;font-size:12px;color:var(--muted)}.graded.unrecorded{color:var(--bad)}.qtext,.lone,.qsrc{overflow-wrap:anywhere}.results{position:relative;max-width:420px;border-radius:28px 8px;overflow:hidden;border:1px solid var(--line);box-shadow:var(--sh-2);background:linear-gradient(180deg,#fff,#fbfdfb);padding:22px;text-align:left;animation:cardIn .5s var(--spring) both}.results-top{display:flex;align-items:center;gap:16px}.results .ring .val{font-family:var(--serif);font-size:26px;font-weight:700;color:var(--forest)}.results-head h3{font-family:var(--serif);font-size:19px;color:var(--forest);margin:0 0 4px}.results-head .sub{color:var(--muted);font-size:12.5px;line-height:1.5}.missed{display:flex;flex-direction:column;gap:8px}.miss{display:flex;align-items:center;gap:10px;font-size:12.5px;color:var(--ink-2)}.miss .mx{width:20px;height:20px;flex-shrink:0;border-radius:50%;background:var(--bad-soft);color:var(--bad);display:grid;place-items:center}.miss .mq{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.results .again{width:100%;margin-top:18px}.confetti{position:absolute;top:0;left:0;right:0;height:0;pointer-events:none}.confetti i{position:absolute;top:0;width:8px;height:12px;border-radius:2px;opacity:0;animation:fall 1.4s var(--ease) forwards}.details{width:300px;border-left:1px solid var(--sep);background:var(--n-2);display:flex;flex-direction:column;flex-shrink:0;overflow-y:auto}.details .hero{padding:24px 20px 20px;text-align:center;border-bottom:1px solid var(--line)}.details .hero .mk{width:66px;height:66px;border-radius:20px 7px;overflow:hidden;margin:0 auto 13px;background:var(--grad-dark);display:grid;place-items:center;box-shadow:var(--sh-2)}.details .hero h3{font-family:var(--serif);font-size:20px;color:var(--forest);margin:0 0 2px}.details .hero .by{font-size:12px;color:var(--muted)}.details .hero .pill{display:inline-flex;align-items:center;gap:6px;margin-top:12px;font-size:11.5px;color:var(--emerald-2);background:var(--emerald-soft);border:1px solid var(--emerald-line);border-radius:99px;padding:4px 11px;font-weight:600}.details .hero .pill .p{width:7px;height:7px;border-radius:50%;background:var(--avail)}.dsec{padding:16px 20px;border-bottom:1px solid var(--line)}.dsec h4{font-size:10.5px;letter-spacing:1.2px;text-transform:uppercase;color:var(--faint);margin:0 0 10px;font-weight:700}.dsec p{margin:0;font-size:12.5px;line-height:1.55;color:var(--ink-2)}.steps{display:flex;flex-direction:column;gap:11px}.step{display:flex;gap:11px;align-items:flex-start;font-size:12.5px;color:var(--ink-2)}.step .n{width:22px;height:22px;flex-shrink:0;border-radius:7px 3px;background:var(--grad-dark);color:var(--mint);font-weight:700;font-size:11px;display:grid;place-items:center}.deck-title{margin:0 0 10px;font-size:13px;font-weight:600;color:var(--ink);line-height:1.4;word-break:break-word}.dstats{display:flex;gap:10px}.dstat{flex:1;border:1px solid var(--line);border-radius:12px 5px;padding:11px 8px;text-align:center;background:#fff}.dstat b{display:block;font-family:var(--serif);font-size:21px;color:var(--forest);line-height:1}.dstat span{font-size:10px;color:var(--faint);letter-spacing:.3px;text-transform:uppercase}.prog{display:flex;align-items:center;gap:14px;margin-bottom:14px}.ring{position:relative;flex-shrink:0;display:grid;place-items:center}.ring .rval{font-family:var(--serif);font-size:17px;color:var(--forest);letter-spacing:-.3px}.pline{margin:0;font-size:12.5px;line-height:1.5;color:var(--muted)}.pline b{color:var(--ink);font-size:14px}.runs{display:flex;flex-direction:column;gap:8px}.run{display:flex;align-items:center;gap:10px;font-size:12.5px;color:var(--ink-2)}.run .lab{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.run.now .lab{font-weight:700;color:var(--ink)}.run.next{opacity:.45}.run .sc{font-family:var(--mono);font-size:10.5px;color:var(--faint)}.run .bars{display:flex;gap:2px}.run .bars i{width:12px;height:5px;border-radius:2px;background:#e0e5e0;transition:background .3s}.run .bars i.ok{background:var(--emerald)}.run .bars i.no{background:var(--bad)}.insights{display:flex;flex-direction:column;gap:12px}.insight{display:flex;flex-direction:column;gap:5px}.insight-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;font-size:12.5px;color:var(--ink-2)}.insight-head span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.insight-head b{font-family:var(--mono);font-size:11px;color:var(--forest)}.insight-track{display:block;height:6px;border-radius:3px;background:#e1e6e2;overflow:hidden}.insight-track i{display:block;height:100%;border-radius:inherit;background:var(--emerald)}.insight small{font-size:10.5px;color:var(--faint)}@keyframes rise{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}@keyframes riseR{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}@keyframes cardIn{0%{opacity:0;transform:translateY(16px) scale(.985)}to{opacity:1;transform:none}}@keyframes choiceIn{0%{opacity:0;transform:translate(-10px)}to{opacity:1;transform:none}}@keyframes pop{0%{transform:scale(.5)}60%{transform:scale(1.18)}to{transform:scale(1)}}@keyframes blink{0%,60%,to{opacity:.3;transform:translateY(0)}30%{opacity:1;transform:translateY(-3px)}}@keyframes fall{0%{opacity:1;transform:translateY(0) rotate(0)}to{opacity:0;transform:translateY(320px) rotate(320deg)}}@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}.live-insights{display:none}@media(max-width:1120px){.details{display:none}.live-insights{display:block;background:var(--n-2);border:1px solid var(--sep);border-radius:8px;margin-bottom:16px}.live-insights summary{cursor:pointer;padding:12px 20px;color:var(--forest)}}@media(max-width:840px){.rail{display:none}.list{width:86px}.list .name,.list .prev,.list-top h1,.search,.tabs,.chat .time{display:none}.chat{justify-content:center;padding:9px 0;margin:0}.window{height:calc(100vh - 24px)}.stage{padding:12px}.messages{padding:18px 14px 8px}}.modes{display:flex;gap:8px;margin-top:12px;max-width:400px}.modes .start{margin-top:0;flex:1;padding:9px 6px;font-size:12.5px;background:transparent;color:var(--faint);border-color:var(--line)}.modes .start[aria-pressed=true]{background:var(--grad-dark);color:#fff;border-color:transparent}.modes .start{line-height:1.25;text-align:center}@media(max-width:620px){.modes{flex-direction:column}.modes .start{flex:1 1 auto}}
|
package/client/dist/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>FlashLearn</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-BfT0dxQA.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BpCwS7Lt.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/dist/index.js
CHANGED
|
@@ -121,7 +121,7 @@ async function runCli(args2, service2, io) {
|
|
|
121
121
|
io.stdout(" # Generate study cards from this repository");
|
|
122
122
|
io.stdout(` flashlearn generate --project ${quoteArgument(directory)}`);
|
|
123
123
|
} else {
|
|
124
|
-
if (!await generateForStudy(service2, io, directory, options)) return 1;
|
|
124
|
+
if (!await generateForStudy(service2, io, directory, await generationOptions(io, options))) return 1;
|
|
125
125
|
io.stdout("");
|
|
126
126
|
io.stdout("Next:");
|
|
127
127
|
io.stdout(" # Start the local learning experience");
|
|
@@ -145,7 +145,7 @@ Then:
|
|
|
145
145
|
Or approve empty-deck generation with start --yes.`);
|
|
146
146
|
return 1;
|
|
147
147
|
}
|
|
148
|
-
if (!await generateForStudy(service2, io, directory)) return 1;
|
|
148
|
+
if (!await generateForStudy(service2, io, directory, await generationOptions(io))) return 1;
|
|
149
149
|
}
|
|
150
150
|
await service2.start(directory, options);
|
|
151
151
|
const url = `http://${options.host ?? "localhost"}:${options.port ?? 4173}`;
|
|
@@ -167,6 +167,57 @@ Or approve empty-deck generation with start --yes.`);
|
|
|
167
167
|
return 1;
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
+
async function generationOptions(io, options = {}) {
|
|
171
|
+
if (io.endpointConfigured) {
|
|
172
|
+
io.stderr("Using the configured inference endpoint.");
|
|
173
|
+
return options;
|
|
174
|
+
}
|
|
175
|
+
if (io.confirm && await io.detectCopilot?.()) {
|
|
176
|
+
const approved = await io.confirm("GitHub Copilot CLI was found on PATH. Use `copilot -p` to generate cards from source files? [y/N] ");
|
|
177
|
+
if (approved) {
|
|
178
|
+
io.stderr("Using GitHub Copilot CLI for code card generation.");
|
|
179
|
+
return { ...options, provider: { kind: "copilot" } };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (!io.prompt) return deterministicOptions(io, options, "No interactive provider setup is available.");
|
|
183
|
+
const choice = (await io.prompt("Generation provider [deterministic/openai/claude/custom] (default deterministic): "))?.trim().toLowerCase();
|
|
184
|
+
if (!choice || choice === "deterministic") return deterministicOptions(io, options, "Deterministic generation selected.");
|
|
185
|
+
let provider = null;
|
|
186
|
+
if (choice === "openai") {
|
|
187
|
+
const apiKey = await requiredSecret(io, "OpenAI API key (current run only): ");
|
|
188
|
+
const model = await withDefault(io, "OpenAI model [gpt-4o-mini]: ", "gpt-4o-mini");
|
|
189
|
+
if (apiKey && model) provider = { kind: "endpoint", url: "https://api.openai.com/v1/chat/completions", model, apiKey };
|
|
190
|
+
} else if (choice === "claude") {
|
|
191
|
+
const apiKey = await requiredSecret(io, "Anthropic API key (current run only): ");
|
|
192
|
+
const model = await withDefault(io, "Claude model [claude-sonnet-4-5]: ", "claude-sonnet-4-5");
|
|
193
|
+
if (apiKey && model) provider = { kind: "anthropic", apiKey, model };
|
|
194
|
+
} else if (choice === "custom") {
|
|
195
|
+
const url = (await io.prompt("OpenAI-compatible chat-completions URL: "))?.trim();
|
|
196
|
+
const model = (await io.prompt("Model or deployment name: "))?.trim();
|
|
197
|
+
const apiKey = (await io.prompt("API key (optional, current run only): ", true))?.trim();
|
|
198
|
+
const authHeader = apiKey ? await withDefault(io, "Authentication header [Authorization]: ", "Authorization") : null;
|
|
199
|
+
if (url && model) {
|
|
200
|
+
if (!apiKey) provider = { kind: "endpoint", url, model };
|
|
201
|
+
else if (authHeader) provider = { kind: "endpoint", url, model, apiKey, authHeader };
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
return deterministicOptions(io, options, `Unknown provider "${choice}".`);
|
|
205
|
+
}
|
|
206
|
+
if (!provider) return deterministicOptions(io, options, "Provider setup was incomplete.");
|
|
207
|
+
io.stderr("Using the selected AI provider. Source files will be sent to that provider; the API key will not be saved.");
|
|
208
|
+
return { ...options, provider };
|
|
209
|
+
}
|
|
210
|
+
async function requiredSecret(io, message) {
|
|
211
|
+
return (await io.prompt?.(message, true))?.trim() || null;
|
|
212
|
+
}
|
|
213
|
+
async function withDefault(io, message, fallback) {
|
|
214
|
+
const value = await io.prompt?.(message);
|
|
215
|
+
return value === null || value === void 0 ? null : value.trim() || fallback;
|
|
216
|
+
}
|
|
217
|
+
function deterministicOptions(io, options, reason) {
|
|
218
|
+
io.stderr(`${reason} Falling back to deterministic generation; no source code will be sent to an AI provider.`);
|
|
219
|
+
return { ...options, provider: { kind: "deterministic" } };
|
|
220
|
+
}
|
|
170
221
|
async function generateForStudy(service2, io, directory, options) {
|
|
171
222
|
io.stderr("Generating study cards (may use the configured AI endpoint)...");
|
|
172
223
|
const cards = await service2.generate(directory, options);
|
|
@@ -327,7 +378,7 @@ var init_cli = __esm({
|
|
|
327
378
|
"use strict";
|
|
328
379
|
init_paths();
|
|
329
380
|
init_yaml();
|
|
330
|
-
CLI_VERSION = "0.
|
|
381
|
+
CLI_VERSION = "0.2.0";
|
|
331
382
|
HELP = `Usage: flashlearn <command> [directory] [options]
|
|
332
383
|
|
|
333
384
|
Commands:
|
|
@@ -830,7 +881,7 @@ var init_endpoint = __esm({
|
|
|
830
881
|
}));
|
|
831
882
|
}
|
|
832
883
|
/** Returns the assistant message, or null when the call fails for any reason. */
|
|
833
|
-
async requestReply(
|
|
884
|
+
async requestReply(prompt2) {
|
|
834
885
|
const controller = new AbortController();
|
|
835
886
|
const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
836
887
|
try {
|
|
@@ -841,7 +892,7 @@ var init_endpoint = __esm({
|
|
|
841
892
|
model: this.config.model,
|
|
842
893
|
messages: [
|
|
843
894
|
{ role: "system", content: SYSTEM_PROMPT },
|
|
844
|
-
{ role: "user", content:
|
|
895
|
+
{ role: "user", content: prompt2 }
|
|
845
896
|
],
|
|
846
897
|
temperature: 0
|
|
847
898
|
}),
|
|
@@ -1292,6 +1343,11 @@ function createFlashLearnServer(services) {
|
|
|
1292
1343
|
const method = request.method === "HEAD" ? "GET" : request.method;
|
|
1293
1344
|
if (method === "GET" && url.pathname === "/api/cards")
|
|
1294
1345
|
return json(response, 200, await services.listCards(), body);
|
|
1346
|
+
if (method === "GET" && url.pathname === "/api/project") {
|
|
1347
|
+
const declared = (await services.project?.())?.name;
|
|
1348
|
+
const name = typeof declared === "string" && declared.trim() ? declared.trim() : null;
|
|
1349
|
+
return json(response, 200, { name }, body);
|
|
1350
|
+
}
|
|
1295
1351
|
if (method === "GET" && url.pathname === "/api/cards/next") {
|
|
1296
1352
|
const card = await services.nextCard();
|
|
1297
1353
|
if (!card)
|
|
@@ -1637,15 +1693,166 @@ var init_dist4 = __esm({
|
|
|
1637
1693
|
}
|
|
1638
1694
|
});
|
|
1639
1695
|
|
|
1696
|
+
// packages/cli/src/project-name.ts
|
|
1697
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
1698
|
+
import { join as join6 } from "node:path";
|
|
1699
|
+
async function readProjectName(root) {
|
|
1700
|
+
for (const source of SOURCES) {
|
|
1701
|
+
const contents = await readFile4(join6(root, source.file), "utf8").catch(() => null);
|
|
1702
|
+
if (contents === null) continue;
|
|
1703
|
+
const name = source.read(contents)?.trim();
|
|
1704
|
+
if (name) return name;
|
|
1705
|
+
}
|
|
1706
|
+
return null;
|
|
1707
|
+
}
|
|
1708
|
+
var SOURCES;
|
|
1709
|
+
var init_project_name = __esm({
|
|
1710
|
+
"packages/cli/src/project-name.ts"() {
|
|
1711
|
+
"use strict";
|
|
1712
|
+
SOURCES = [
|
|
1713
|
+
{
|
|
1714
|
+
file: "package.json",
|
|
1715
|
+
read: (contents) => {
|
|
1716
|
+
try {
|
|
1717
|
+
const name = JSON.parse(contents).name;
|
|
1718
|
+
return typeof name === "string" ? name : void 0;
|
|
1719
|
+
} catch {
|
|
1720
|
+
return void 0;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
},
|
|
1724
|
+
{
|
|
1725
|
+
// `module k8s.io/kubernetes` names the project in its last segment.
|
|
1726
|
+
file: "go.mod",
|
|
1727
|
+
read: (contents) => contents.match(/^module\s+(\S+)/m)?.[1]?.split("/").pop()
|
|
1728
|
+
}
|
|
1729
|
+
];
|
|
1730
|
+
}
|
|
1731
|
+
});
|
|
1732
|
+
|
|
1733
|
+
// packages/cli/src/providers.ts
|
|
1734
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
1735
|
+
import { promisify as promisify2 } from "node:util";
|
|
1736
|
+
function promptFor(input, includeSystem = true) {
|
|
1737
|
+
const content = input.content.length > MAX_CONTENT_CHARS2 ? `${input.content.slice(0, MAX_CONTENT_CHARS2)}
|
|
1738
|
+
... file truncated ...` : input.content;
|
|
1739
|
+
const prompt2 = `File: ${input.path}
|
|
1740
|
+
Write at most ${MAX_CARDS} cards.
|
|
1741
|
+
|
|
1742
|
+
${content}`;
|
|
1743
|
+
return includeSystem ? `${SYSTEM_PROMPT2}
|
|
1744
|
+
|
|
1745
|
+
${prompt2}` : prompt2;
|
|
1746
|
+
}
|
|
1747
|
+
function attributedCards(reply, input) {
|
|
1748
|
+
const fenced = /```(?:json)?\s*([\s\S]*?)```/.exec(reply);
|
|
1749
|
+
const candidate = fenced?.[1]?.trim() ?? reply.trim();
|
|
1750
|
+
const start = candidate.indexOf("{");
|
|
1751
|
+
const end = candidate.lastIndexOf("}");
|
|
1752
|
+
if (start === -1 || end <= start) return [];
|
|
1753
|
+
try {
|
|
1754
|
+
const parsed = JSON.parse(candidate.slice(start, end + 1));
|
|
1755
|
+
if (!Array.isArray(parsed.cards)) return [];
|
|
1756
|
+
return parsed.cards.flatMap((entry) => {
|
|
1757
|
+
if (typeof entry !== "object" || entry === null) return [];
|
|
1758
|
+
const { question, answer } = entry;
|
|
1759
|
+
if (typeof question !== "string" || typeof answer !== "string") return [];
|
|
1760
|
+
if (!question.trim() || !answer.trim()) return [];
|
|
1761
|
+
return [{ question: question.trim(), answer: answer.trim(), source: { path: input.path, sha: input.sha } }];
|
|
1762
|
+
}).slice(0, MAX_CARDS);
|
|
1763
|
+
} catch {
|
|
1764
|
+
return [];
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
async function runCopilot(prompt2) {
|
|
1768
|
+
try {
|
|
1769
|
+
const { stdout } = await execFileAsync2("copilot", [
|
|
1770
|
+
"-p",
|
|
1771
|
+
prompt2,
|
|
1772
|
+
"--silent",
|
|
1773
|
+
"--no-custom-instructions",
|
|
1774
|
+
"--no-ask-user",
|
|
1775
|
+
"--no-color"
|
|
1776
|
+
], { timeout: 12e4, maxBuffer: 1e6 });
|
|
1777
|
+
return stdout;
|
|
1778
|
+
} catch {
|
|
1779
|
+
return null;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
var execFileAsync2, CODE_EXTENSIONS2, MAX_CONTENT_CHARS2, MAX_CARDS, SYSTEM_PROMPT2, CopilotExtractor, AnthropicExtractor;
|
|
1783
|
+
var init_providers = __esm({
|
|
1784
|
+
"packages/cli/src/providers.ts"() {
|
|
1785
|
+
"use strict";
|
|
1786
|
+
execFileAsync2 = promisify2(execFile2);
|
|
1787
|
+
CODE_EXTENSIONS2 = /\.(go|js|jsx|ts|tsx)$/i;
|
|
1788
|
+
MAX_CONTENT_CHARS2 = 24e3;
|
|
1789
|
+
MAX_CARDS = 5;
|
|
1790
|
+
SYSTEM_PROMPT2 = 'Write onboarding flashcards grounded only in the supplied source file. Prefer behavior, control flow, and intent. Never invent APIs, paths, or behavior. Reply with JSON only: {"cards":[{"question":"...","answer":"..."}]}. Return an empty cards array when nothing is worth asking.';
|
|
1791
|
+
CopilotExtractor = class {
|
|
1792
|
+
constructor(run = runCopilot) {
|
|
1793
|
+
this.run = run;
|
|
1794
|
+
}
|
|
1795
|
+
async extract(input) {
|
|
1796
|
+
if (!CODE_EXTENSIONS2.test(input.path) || input.content.trim().length === 0) return [];
|
|
1797
|
+
const reply = await this.run(promptFor(input));
|
|
1798
|
+
return reply === null ? [] : attributedCards(reply, input);
|
|
1799
|
+
}
|
|
1800
|
+
};
|
|
1801
|
+
AnthropicExtractor = class {
|
|
1802
|
+
constructor(apiKey, model, fetchImpl = fetch) {
|
|
1803
|
+
this.apiKey = apiKey;
|
|
1804
|
+
this.model = model;
|
|
1805
|
+
this.fetchImpl = fetchImpl;
|
|
1806
|
+
}
|
|
1807
|
+
async extract(input) {
|
|
1808
|
+
if (!CODE_EXTENSIONS2.test(input.path) || input.content.trim().length === 0) return [];
|
|
1809
|
+
const controller = new AbortController();
|
|
1810
|
+
const timeout = setTimeout(() => controller.abort(), 3e4);
|
|
1811
|
+
try {
|
|
1812
|
+
const response = await this.fetchImpl("https://api.anthropic.com/v1/messages", {
|
|
1813
|
+
method: "POST",
|
|
1814
|
+
headers: {
|
|
1815
|
+
"content-type": "application/json",
|
|
1816
|
+
"x-api-key": this.apiKey,
|
|
1817
|
+
"anthropic-version": "2023-06-01"
|
|
1818
|
+
},
|
|
1819
|
+
body: JSON.stringify({
|
|
1820
|
+
model: this.model,
|
|
1821
|
+
max_tokens: 2e3,
|
|
1822
|
+
system: SYSTEM_PROMPT2,
|
|
1823
|
+
messages: [{ role: "user", content: promptFor(input, false) }]
|
|
1824
|
+
}),
|
|
1825
|
+
signal: controller.signal
|
|
1826
|
+
});
|
|
1827
|
+
if (!response.ok) return [];
|
|
1828
|
+
const payload = await response.json();
|
|
1829
|
+
const reply = payload.content?.find((part) => part.type === "text")?.text;
|
|
1830
|
+
return typeof reply === "string" ? attributedCards(reply, input) : [];
|
|
1831
|
+
} catch {
|
|
1832
|
+
return [];
|
|
1833
|
+
} finally {
|
|
1834
|
+
clearTimeout(timeout);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
});
|
|
1840
|
+
|
|
1640
1841
|
// packages/cli/src/production.ts
|
|
1641
1842
|
import { stat } from "node:fs/promises";
|
|
1642
|
-
import { join as
|
|
1843
|
+
import { join as join7 } from "node:path";
|
|
1643
1844
|
function createProductionDependencies() {
|
|
1644
1845
|
return {
|
|
1645
1846
|
initializeStore,
|
|
1646
|
-
generateCards: (root, options) =>
|
|
1647
|
-
|
|
1648
|
-
|
|
1847
|
+
generateCards: (root, options) => {
|
|
1848
|
+
if (!options?.provider) return generateCards(root, void 0, options);
|
|
1849
|
+
const { provider, ...scope } = options;
|
|
1850
|
+
const extractor = extractorFor(provider);
|
|
1851
|
+
const concurrency = provider.kind === "copilot" ? 1 : 8;
|
|
1852
|
+
return new ExtractionService(extractor, concurrency).generateFromRepository(root, scope);
|
|
1853
|
+
},
|
|
1854
|
+
createCardRepository: (root) => new JsonCardRepository(join7(flashlearnRoot(root), "cards.json")),
|
|
1855
|
+
createReviewRepository: (root) => new JsonReviewRepository(join7(flashlearnRoot(root), "review.json")),
|
|
1649
1856
|
scheduleReview,
|
|
1650
1857
|
selectNextCard,
|
|
1651
1858
|
createServer: createFlashLearnServer,
|
|
@@ -1660,6 +1867,7 @@ function createProductionDependencies() {
|
|
|
1660
1867
|
});
|
|
1661
1868
|
});
|
|
1662
1869
|
},
|
|
1870
|
+
readProjectName,
|
|
1663
1871
|
isDirectory: async (path) => {
|
|
1664
1872
|
try {
|
|
1665
1873
|
return (await stat(path)).isDirectory();
|
|
@@ -1671,6 +1879,11 @@ function createProductionDependencies() {
|
|
|
1671
1879
|
now: () => /* @__PURE__ */ new Date()
|
|
1672
1880
|
};
|
|
1673
1881
|
}
|
|
1882
|
+
function extractorFor(provider) {
|
|
1883
|
+
if (provider.kind === "deterministic") return deterministicExtractor();
|
|
1884
|
+
const code = provider.kind === "copilot" ? new CopilotExtractor() : provider.kind === "anthropic" ? new AnthropicExtractor(provider.apiKey, provider.model) : new EndpointExtractor(provider);
|
|
1885
|
+
return new CompositeExtractor(code, new MarkdownExtractor());
|
|
1886
|
+
}
|
|
1674
1887
|
var init_production = __esm({
|
|
1675
1888
|
"packages/cli/src/production.ts"() {
|
|
1676
1889
|
"use strict";
|
|
@@ -1679,6 +1892,8 @@ var init_production = __esm({
|
|
|
1679
1892
|
init_dist3();
|
|
1680
1893
|
init_dist4();
|
|
1681
1894
|
init_paths();
|
|
1895
|
+
init_project_name();
|
|
1896
|
+
init_providers();
|
|
1682
1897
|
}
|
|
1683
1898
|
});
|
|
1684
1899
|
|
|
@@ -1727,6 +1942,7 @@ var init_workstream5 = __esm({
|
|
|
1727
1942
|
const reviews = this.dependencies.createReviewRepository(rootPath);
|
|
1728
1943
|
const services = {
|
|
1729
1944
|
listCards: () => cards.list(),
|
|
1945
|
+
project: async () => ({ name: await this.dependencies.readProjectName(root) }),
|
|
1730
1946
|
getCard: (id) => cards.get(id),
|
|
1731
1947
|
nextCard: async () => {
|
|
1732
1948
|
const allCards = await cards.list();
|
|
@@ -1793,6 +2009,7 @@ var init_workstream5 = __esm({
|
|
|
1793
2009
|
|
|
1794
2010
|
// packages/cli/src/confirm.ts
|
|
1795
2011
|
import { createInterface } from "node:readline/promises";
|
|
2012
|
+
import { Writable } from "node:stream";
|
|
1796
2013
|
async function confirm(message) {
|
|
1797
2014
|
if (!process.stdin.isTTY || !process.stderr.isTTY) return false;
|
|
1798
2015
|
const reader = createInterface({ input: process.stdin, output: process.stderr });
|
|
@@ -1803,12 +2020,48 @@ async function confirm(message) {
|
|
|
1803
2020
|
reader.close();
|
|
1804
2021
|
}
|
|
1805
2022
|
}
|
|
2023
|
+
async function prompt(message, secret = false) {
|
|
2024
|
+
if (!process.stdin.isTTY || !process.stderr.isTTY) return null;
|
|
2025
|
+
if (!secret) {
|
|
2026
|
+
const reader2 = createInterface({ input: process.stdin, output: process.stderr });
|
|
2027
|
+
try {
|
|
2028
|
+
return await reader2.question(message);
|
|
2029
|
+
} finally {
|
|
2030
|
+
reader2.close();
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
process.stderr.write(message);
|
|
2034
|
+
const muted = new Writable({ write(_chunk, _encoding, callback) {
|
|
2035
|
+
callback();
|
|
2036
|
+
} });
|
|
2037
|
+
const reader = createInterface({ input: process.stdin, output: muted, terminal: true });
|
|
2038
|
+
try {
|
|
2039
|
+
const answer = await reader.question("");
|
|
2040
|
+
process.stderr.write("\n");
|
|
2041
|
+
return answer;
|
|
2042
|
+
} finally {
|
|
2043
|
+
reader.close();
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
1806
2046
|
var init_confirm = __esm({
|
|
1807
2047
|
"packages/cli/src/confirm.ts"() {
|
|
1808
2048
|
"use strict";
|
|
1809
2049
|
}
|
|
1810
2050
|
});
|
|
1811
2051
|
|
|
2052
|
+
// packages/cli/src/copilot.ts
|
|
2053
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
2054
|
+
function detectCopilot() {
|
|
2055
|
+
return new Promise((resolve4) => {
|
|
2056
|
+
execFile3("copilot", ["--version"], { timeout: 5e3 }, (error) => resolve4(error === null));
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2059
|
+
var init_copilot = __esm({
|
|
2060
|
+
"packages/cli/src/copilot.ts"() {
|
|
2061
|
+
"use strict";
|
|
2062
|
+
}
|
|
2063
|
+
});
|
|
2064
|
+
|
|
1812
2065
|
// packages/cli/src/index.ts
|
|
1813
2066
|
var src_exports = {};
|
|
1814
2067
|
var dependencies, service;
|
|
@@ -1819,13 +2072,17 @@ var init_src = __esm({
|
|
|
1819
2072
|
init_production();
|
|
1820
2073
|
init_workstream5();
|
|
1821
2074
|
init_confirm();
|
|
2075
|
+
init_copilot();
|
|
1822
2076
|
dependencies = createProductionDependencies();
|
|
1823
2077
|
service = new CliService(dependencies);
|
|
1824
2078
|
process.exitCode = await runCli(process.argv.slice(2), service, {
|
|
1825
2079
|
cwd: process.cwd(),
|
|
1826
2080
|
stdout: (message) => console.log(message),
|
|
1827
2081
|
stderr: (message) => console.error(message),
|
|
1828
|
-
confirm
|
|
2082
|
+
confirm,
|
|
2083
|
+
prompt,
|
|
2084
|
+
detectCopilot,
|
|
2085
|
+
endpointConfigured: Boolean(process.env.FLASHLEARN_ENDPOINT_URL?.trim() && process.env.FLASHLEARN_ENDPOINT_MODEL?.trim())
|
|
1829
2086
|
});
|
|
1830
2087
|
}
|
|
1831
2088
|
});
|