@vue-skuilder/platform-ui 0.1.35 → 0.1.36
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/dist/assets/{About-CYoEhp5l.js → About-eVevEMqh.js} +2 -2
- package/dist/assets/{About-CYoEhp5l.js.map → About-eVevEMqh.js.map} +1 -1
- package/dist/assets/AdminDashboard-C_oJ8NGZ.js +2 -0
- package/dist/assets/{AdminDashboard-DO3Mo6_x.js.map → AdminDashboard-C_oJ8NGZ.js.map} +1 -1
- package/dist/assets/{ClassroomCtrlPanel-DkBMgZJU.js → ClassroomCtrlPanel-DanEeAZ0.js} +2 -2
- package/dist/assets/{ClassroomCtrlPanel-DkBMgZJU.js.map → ClassroomCtrlPanel-DanEeAZ0.js.map} +1 -1
- package/dist/assets/{Classrooms-BRwjFo6r.js → Classrooms-OrG6VOnx.js} +2 -2
- package/dist/assets/{Classrooms-BRwjFo6r.js.map → Classrooms-OrG6VOnx.js.map} +1 -1
- package/dist/assets/{CourseRouter-BrofD0lZ.js → CourseRouter-CK8Xh2h2.js} +2 -2
- package/dist/assets/{CourseRouter-BrofD0lZ.js.map → CourseRouter-CK8Xh2h2.js.map} +1 -1
- package/dist/assets/CourseWare-BTFRjgBR-D750E7i0.css +1 -0
- package/dist/assets/{CourseWare-BTFRjgBR-ca7as3tn.js → CourseWare-BTFRjgBR-OzjKW1B2.js} +3 -3
- package/dist/assets/{CourseWare-BTFRjgBR-ca7as3tn.js.map → CourseWare-BTFRjgBR-OzjKW1B2.js.map} +1 -1
- package/dist/assets/{Courses-DyZS7Cle.js → Courses-DB0JFz1Q.js} +2 -2
- package/dist/assets/{Courses-DyZS7Cle.js.map → Courses-DB0JFz1Q.js.map} +1 -1
- package/dist/assets/EloModeration-BmU0CqZt.js +2 -0
- package/dist/assets/{EloModeration-B8hFSqwy.js.map → EloModeration-BmU0CqZt.js.map} +1 -1
- package/dist/assets/{JoinCode-DOLzN-p-.js → JoinCode-KoSLXpUy.js} +2 -2
- package/dist/assets/{JoinCode-DOLzN-p-.js.map → JoinCode-KoSLXpUy.js.map} +1 -1
- package/dist/assets/{NewCourseDialog-CjeJyyc3.js → NewCourseDialog-BXxQ1cvK.js} +2 -2
- package/dist/assets/{NewCourseDialog-CjeJyyc3.js.map → NewCourseDialog-BXxQ1cvK.js.map} +1 -1
- package/dist/assets/{ReleaseNotes-D9KhPUiR.js → ReleaseNotes-CERYwZro.js} +2 -2
- package/dist/assets/{ReleaseNotes-D9KhPUiR.js.map → ReleaseNotes-CERYwZro.js.map} +1 -1
- package/dist/assets/{RequestPasswordReset-CdzOhOXs.js → RequestPasswordReset-Bc4FHaYS.js} +2 -2
- package/dist/assets/{RequestPasswordReset-CdzOhOXs.js.map → RequestPasswordReset-Bc4FHaYS.js.map} +1 -1
- package/dist/assets/{ResetPassword-Cu62zkXq.js → ResetPassword-CeR_bmOz.js} +2 -2
- package/dist/assets/{ResetPassword-Cu62zkXq.js.map → ResetPassword-CeR_bmOz.js.map} +1 -1
- package/dist/assets/Study-voro05GB.js +2 -0
- package/dist/assets/{Study-DYkoX3oR.js.map → Study-voro05GB.js.map} +1 -1
- package/dist/assets/TagInformation-1urKQaI-.js +2 -0
- package/dist/assets/{TagInformation-PbQDPmpb.js.map → TagInformation-1urKQaI-.js.map} +1 -1
- package/dist/assets/{User-CIFHdgrZ.js → User-26Hebdw-.js} +2 -2
- package/dist/assets/{User-CIFHdgrZ.js.map → User-26Hebdw-.js.map} +1 -1
- package/dist/assets/{UserStats-DSyaFn7j.js → UserStats-DbWUnAPD.js} +2 -2
- package/dist/assets/{UserStats-DSyaFn7j.js.map → UserStats-DbWUnAPD.js.map} +1 -1
- package/dist/assets/{VerifyEmail-DWS9S3tV.js → VerifyEmail-uix17ueS.js} +2 -2
- package/dist/assets/{VerifyEmail-DWS9S3tV.js.map → VerifyEmail-uix17ueS.js.map} +1 -1
- package/dist/assets/{chess-BbHATAzk-DOhLaMTg.js → chess-BbHATAzk-BhFAwbgX.js} +2 -2
- package/dist/assets/chess-BbHATAzk-BhFAwbgX.js.map +1 -0
- package/dist/assets/chess-BbHATAzk-DB7z_kWx.css +1 -0
- package/dist/assets/chess-X1bmWmh3-C7B3mHa1.js +1 -0
- package/dist/assets/common-ui.es-C18SEA_L.js +1 -0
- package/dist/assets/{common-ui.es-ConLKYrk.js → common-ui.es-p3cgaI_b.js} +4 -4
- package/dist/assets/{common-ui.es-ConLKYrk.js.map → common-ui.es-p3cgaI_b.js.map} +1 -1
- package/dist/assets/dist-CszlUrrD.js +1 -0
- package/dist/assets/dist-D2Tzeiyw.js +1 -0
- package/dist/assets/{dist-DKtzwGWn.js → dist-DA7EuQY2.js} +33 -11
- package/dist/assets/dist-DA7EuQY2.js.map +1 -0
- package/dist/assets/{dist-Daq3OiEc.js → dist-DCY40cJ7.js} +3 -3
- package/dist/assets/dist-DCY40cJ7.js.map +1 -0
- package/dist/assets/{edit-ui.es-DNDxRLE6.js → edit-ui.es-BIV0deYk.js} +2 -2
- package/dist/assets/{edit-ui.es-DNDxRLE6.js.map → edit-ui.es-BIV0deYk.js.map} +1 -1
- package/dist/assets/edit-ui.es-BLMFpJm1.js +1 -0
- package/dist/assets/{french-Dk7YG8Td-Bzxo0iir.js → french-Dk7YG8Td-YK4jNZUN.js} +2 -2
- package/dist/assets/{french-Dk7YG8Td-Bzxo0iir.js.map → french-Dk7YG8Td-YK4jNZUN.js.map} +1 -1
- package/dist/assets/french-evUMlbbq-BbJDdRqK.js +1 -0
- package/dist/assets/index-B-cSF0fq.js +4 -0
- package/dist/assets/{index-B4di3I6o.js.map → index-B-cSF0fq.js.map} +1 -1
- package/dist/assets/{math-B4HbgYf6-DW4In8a5.js → math-B4HbgYf6-CLJIZTjv.js} +2 -2
- package/dist/assets/math-B4HbgYf6-CLJIZTjv.js.map +1 -0
- package/dist/assets/math-B4HbgYf6-CZyvKZtp.css +1 -0
- package/dist/assets/math-DYni7rRl-C6a4BDoN.js +1 -0
- package/dist/assets/piano-BN5Btq91-Cdn8kuW5.js +1 -0
- package/dist/assets/{piano-DF1g6yaX-C9jL6jej.js → piano-DF1g6yaX-AR14jqWm.js} +2 -2
- package/dist/assets/piano-DF1g6yaX-AR14jqWm.js.map +1 -0
- package/dist/assets/piano-DF1g6yaX-BLvDAgl1.css +1 -0
- package/dist/assets/{pitch-CgGJFkZ1-B4qiD-od.js → pitch-CgGJFkZ1-DYkp_AV0.js} +2 -2
- package/dist/assets/{pitch-CgGJFkZ1-B4qiD-od.js.map → pitch-CgGJFkZ1-DYkp_AV0.js.map} +1 -1
- package/dist/assets/pitch-Dn0iNqiS-CJ_97iB4.js +1 -0
- package/dist/assets/{server-RYtUROqF.js → server-Bq50faqp.js} +2 -2
- package/dist/assets/{server-RYtUROqF.js.map → server-Bq50faqp.js.map} +1 -1
- package/dist/assets/{sightsing-BFQ7HRig-gi-f6Gjx.js → sightsing-BFQ7HRig-BNrrORP_.js} +2 -2
- package/dist/assets/sightsing-BFQ7HRig-BNrrORP_.js.map +1 -0
- package/dist/assets/sightsing-BFQ7HRig-DkUGf5Yf.css +1 -0
- package/dist/assets/sightsing-CJX3k0Fd-l4fhB1Aj.js +1 -0
- package/dist/assets/typing-BevtfWlp-B7ZMUAQJ.css +1 -0
- package/dist/assets/{typing-BevtfWlp-a9gMsGkx.js → typing-BevtfWlp-Cl6jtRmX.js} +2 -2
- package/dist/assets/typing-BevtfWlp-Cl6jtRmX.js.map +1 -0
- package/dist/assets/typing-k-ojjO7G-CHgxm7Rx.js +1 -0
- package/dist/assets/{word-work-BOnRlZgd-DhZkqecP.js → word-work-BOnRlZgd-CGV2xRx9.js} +2 -2
- package/dist/assets/{word-work-BOnRlZgd-DhZkqecP.js.map → word-work-BOnRlZgd-CGV2xRx9.js.map} +1 -1
- package/dist/assets/word-work-Dd6tIKrt-BjF3-3lq.js +1 -0
- package/dist/index.html +3 -3
- package/dist/sw.js +1 -1
- package/dist/sw.js.map +1 -1
- package/package.json +7 -7
- package/src/dev/Playtest.vue +254 -0
- package/dist/assets/AdminDashboard-DO3Mo6_x.js +0 -2
- package/dist/assets/EloModeration-B8hFSqwy.js +0 -2
- package/dist/assets/Study-DYkoX3oR.js +0 -2
- package/dist/assets/TagInformation-PbQDPmpb.js +0 -2
- package/dist/assets/chess-BbHATAzk-DOhLaMTg.js.map +0 -1
- package/dist/assets/chess-X1bmWmh3-C3HyTLIE.js +0 -1
- package/dist/assets/common-ui.es-BmXCkW19.js +0 -1
- package/dist/assets/dist-DKtzwGWn.js.map +0 -1
- package/dist/assets/dist-Daq3OiEc.js.map +0 -1
- package/dist/assets/dist-EH1RSdAN.js +0 -1
- package/dist/assets/dist-huY4PEit.js +0 -1
- package/dist/assets/edit-ui.es-C6Itr3tP.js +0 -1
- package/dist/assets/french-evUMlbbq-D88z2AaV.js +0 -1
- package/dist/assets/index-B4di3I6o.js +0 -4
- package/dist/assets/math-B4HbgYf6-DW4In8a5.js.map +0 -1
- package/dist/assets/math-DYni7rRl-BLRdDTmX.js +0 -1
- package/dist/assets/piano-BN5Btq91-D1ljSgCc.js +0 -1
- package/dist/assets/piano-DF1g6yaX-C9jL6jej.js.map +0 -1
- package/dist/assets/pitch-Dn0iNqiS-Vbm_Ue9p.js +0 -1
- package/dist/assets/sightsing-BFQ7HRig-gi-f6Gjx.js.map +0 -1
- package/dist/assets/sightsing-CJX3k0Fd-CLDxoSv_.js +0 -1
- package/dist/assets/typing-BevtfWlp-a9gMsGkx.js.map +0 -1
- package/dist/assets/typing-k-ojjO7G-CHVzRXi1.js +0 -1
- package/dist/assets/word-work-Dd6tIKrt-CVY1zayr.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./vue.runtime.esm-bundler-C3q8JS9f.js";import"./common-ui.es-p3cgaI_b.js";import"./dist-leWgtXBf.js";import"./MarkdownRenderer-DoVbFpA6-CvaBjTS8.js";import"./dist-DA7EuQY2.js";import"./CourseWare-BTFRjgBR-OzjKW1B2.js";import"./chess-BbHATAzk-BhFAwbgX.js";import"./french-Dk7YG8Td-YK4jNZUN.js";import"./math-B4HbgYf6-CLJIZTjv.js";import"./piano-DF1g6yaX-AR14jqWm.js";import"./pitch-CgGJFkZ1-DYkp_AV0.js";import"./sightsing-BFQ7HRig-BNrrORP_.js";import"./typing-BevtfWlp-Cl6jtRmX.js";import"./word-work-BOnRlZgd-CGV2xRx9.js";import{a as e,r as t,t as n}from"./dist-DCY40cJ7.js";export{n as allCourseWare,t as defaultCourse,e as loadAllSubcourses};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./dist-leWgtXBf.js";import{n as e}from"./dist-DA7EuQY2.js";export{e as CourseLookup};
|
|
@@ -11,8 +11,8 @@ Please double-check your map/reduce function.`),guardedConsole(`error`,t,n)}}fun
|
|
|
11
11
|
`)===0?e.substr(1,e.length):e}).forEach(function(e){var n=e.split(`:`),r=n.shift().trim();if(r){var a=n.join(`:`).trim();try{t.append(r,a)}catch(e){console.warn(`Response `+e.message)}}}),t}Body.call(Request.prototype);function Response(e,t){if(!(this instanceof Response))throw TypeError(`Please use the "new" operator, this DOM object constructor cannot be called as a function.`);if(t||(t={}),this.type=`default`,this.status=t.status===void 0?200:t.status,this.status<200||this.status>599)throw RangeError(`Failed to construct 'Response': The status provided (0) is outside the range [200, 599].`);this.ok=this.status>=200&&this.status<300,this.statusText=t.statusText===void 0?``:``+t.statusText,this.headers=new Headers(t.headers),this.url=t.url||``,this._initBody(e)}Body.call(Response.prototype),Response.prototype.clone=function(){return new Response(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new Headers(this.headers),url:this.url})},Response.error=function(){var e=new Response(null,{status:200,statusText:``});return e.ok=!1,e.status=0,e.type=`error`,e};var c=[301,302,303,307,308];Response.redirect=function(e,t){if(c.indexOf(t)===-1)throw RangeError(`Invalid status code`);return new Response(null,{status:t,headers:{location:e}})},t.DOMException=n.DOMException;try{new t.DOMException}catch{t.DOMException=function(e,t){this.message=e,this.name=t,this.stack=Error(e).stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function fetch(e,a){return new Promise(function(o,s){var c=new Request(e,a);if(c.signal&&c.signal.aborted)return s(new t.DOMException(`Aborted`,`AbortError`));var l=new XMLHttpRequest;function abortXhr(){l.abort()}l.onload=function(){var e={statusText:l.statusText,headers:parseHeaders(l.getAllResponseHeaders()||``)};c.url.indexOf(`file://`)===0&&(l.status<200||l.status>599)?e.status=200:e.status=l.status,e.url=`responseURL`in l?l.responseURL:e.headers.get(`X-Request-URL`);var t=`response`in l?l.response:l.responseText;setTimeout(function(){o(new Response(t,e))},0)},l.onerror=function(){setTimeout(function(){s(TypeError(`Network request failed`))},0)},l.ontimeout=function(){setTimeout(function(){s(TypeError(`Network request timed out`))},0)},l.onabort=function(){setTimeout(function(){s(new t.DOMException(`Aborted`,`AbortError`))},0)};function fixUrl(e){try{return e===``&&n.location.href?n.location.href:e}catch{return e}}if(l.open(c.method,fixUrl(c.url),!0),c.credentials===`include`?l.withCredentials=!0:c.credentials===`omit`&&(l.withCredentials=!1),`responseType`in l&&(r.blob?l.responseType=`blob`:r.arrayBuffer&&(l.responseType=`arraybuffer`)),a&&typeof a.headers==`object`&&!(a.headers instanceof Headers||n.Headers&&a.headers instanceof n.Headers)){var u=[];Object.getOwnPropertyNames(a.headers).forEach(function(e){u.push(normalizeName(e)),l.setRequestHeader(e,normalizeValue(a.headers[e]))}),c.headers.forEach(function(e,t){u.indexOf(t)===-1&&l.setRequestHeader(t,e)})}else c.headers.forEach(function(e,t){l.setRequestHeader(t,e)});c.signal&&(c.signal.addEventListener(`abort`,abortXhr),l.onreadystatechange=function(){l.readyState===4&&c.signal.removeEventListener(`abort`,abortXhr)}),l.send(c._bodyInit===void 0?null:c._bodyInit)})}return fetch.polyfill=!0,n.fetch||(n.fetch=fetch,n.Headers=Headers,n.Request=Request,n.Response=Response),t.Headers=Headers,t.Request=Request,t.Response=Response,t.fetch=fetch,t})({})})(r),r.fetch.ponyfill=!0,delete r.fetch.polyfill;var a=n.fetch?n:r;e=a.fetch,e.default=a.fetch,e.fetch=a.fetch,e.Headers=a.Headers,e.Request=a.Request,e.Response=a.Response,t.exports=e})),require_browser=__commonJSMin(((e,t)=>{var n=t.exports={},r,a;function defaultSetTimout(){throw Error(`setTimeout has not been defined`)}function defaultClearTimeout(){throw Error(`clearTimeout has not been defined`)}(function(){try{r=typeof setTimeout==`function`?setTimeout:defaultSetTimout}catch{r=defaultSetTimout}try{a=typeof clearTimeout==`function`?clearTimeout:defaultClearTimeout}catch{a=defaultClearTimeout}})();function runTimeout(e){if(r===setTimeout)return setTimeout(e,0);if((r===defaultSetTimout||!r)&&setTimeout)return r=setTimeout,setTimeout(e,0);try{return r(e,0)}catch{try{return r.call(null,e,0)}catch{return r.call(this,e,0)}}}function runClearTimeout(e){if(a===clearTimeout)return clearTimeout(e);if((a===defaultClearTimeout||!a)&&clearTimeout)return a=clearTimeout,clearTimeout(e);try{return a(e)}catch{try{return a.call(null,e)}catch{return a.call(this,e)}}}var o=[],s=!1,c,l=-1;function cleanUpNextTick(){!s||!c||(s=!1,c.length?o=c.concat(o):l=-1,o.length&&drainQueue())}function drainQueue(){if(!s){var e=runTimeout(cleanUpNextTick);s=!0;for(var t=o.length;t;){for(c=o,o=[];++l<t;)c&&c[l].run();l=-1,t=o.length}c=null,s=!1,runClearTimeout(e)}}n.nextTick=function(e){var t=Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)t[n-1]=arguments[n];o.push(new Item(e,t)),o.length===1&&!s&&runTimeout(drainQueue)};function Item(e,t){this.fun=e,this.array=t}Item.prototype.run=function(){this.fun.apply(null,this.array)},n.title=`browser`,n.browser=!0,n.env={},n.argv=[],n.version=``,n.versions={};function noop(){}n.on=noop,n.addListener=noop,n.once=noop,n.off=noop,n.removeListener=noop,n.removeAllListeners=noop,n.emit=noop,n.prependListener=noop,n.prependOnceListener=noop,n.listeners=function(e){return[]},n.binding=function(e){throw Error(`process.binding is not supported`)},n.cwd=function(){return`/`},n.chdir=function(e){throw Error(`process.chdir is not supported`)},n.umask=function(){return 0}})),import___vite_browser_external=__toESM(require___vite_browser_external(),1),import_browser_ponyfill=__toESM(require_browser_ponyfill(),1),import_browser=__toESM(require_browser(),1),_SessionController2,__defProp=Object.defineProperty,__getOwnPropNames=Object.getOwnPropertyNames,__glob=e=>t=>{var n=e[t];if(n)return n();throw Error(`Module not found in bundle: `+t)},__esm=(e,t)=>function __init(){return e&&(t=(0,e[__getOwnPropNames(e)[0]])(e=0)),t},__export=(e,t)=>{for(var n in t)__defProp(e,n,{get:t[n],enumerable:!0})},init_adminDB=__esm({"src/core/interfaces/adminDB.ts"(){}}),init_classroomDB=__esm({"src/core/interfaces/classroomDB.ts"(){}}),init_SyncStrategy=__esm({"src/impl/common/SyncStrategy.ts"(){}}),isDevelopment,logger,init_logger=__esm({"src/util/logger.ts"(){isDevelopment=typeof process<`u`&&!1,logger={debug:(e,...t)=>{isDevelopment&&console.debug(`[DB:DEBUG] ${e}`,...t)},info:(e,...t)=>{console.info(`[DB:INFO] ${e}`,...t)},warn:(e,...t)=>{console.warn(`[DB:WARN] ${e}`,...t)},error:(e,...t)=>{console.error(`[DB:ERROR] ${e}`,...t)},log:(e,...t)=>{isDevelopment&&console.log(`[DB:LOG] ${e}`,...t)}}}}),GuestUsername,log,DocType,DocTypePrefixes,init_types_legacy=__esm({"src/core/types/types-legacy.ts"(){init_logger(),GuestUsername=`sk-guest-`,log=e=>{logger.log(e)},DocType=(e=>(e.DISPLAYABLE_DATA=`DISPLAYABLE_DATA`,e.CARD=`CARD`,e.DATASHAPE=`DATASHAPE`,e.QUESTIONTYPE=`QUESTION`,e.VIEW=`VIEW`,e.PEDAGOGY=`PEDAGOGY`,e.CARDRECORD=`CARDRECORD`,e.SCHEDULED_CARD=`SCHEDULED_CARD`,e.TAG=`TAG`,e.NAVIGATION_STRATEGY=`NAVIGATION_STRATEGY`,e.STRATEGY_STATE=`STRATEGY_STATE`,e.USER_OUTCOME=`USER_OUTCOME`,e.STRATEGY_LEARNING_STATE=`STRATEGY_LEARNING_STATE`,e))(DocType||{}),DocTypePrefixes={CARD:`c`,DISPLAYABLE_DATA:`dd`,TAG:`TAG`,CARDRECORD:`cardH`,SCHEDULED_CARD:`card_review_`,DATASHAPE:`DATASHAPE`,QUESTION:`QUESTION`,VIEW:`VIEW`,PEDAGOGY:`PEDAGOGY`,NAVIGATION_STRATEGY:`NAVIGATION_STRATEGY`,STRATEGY_STATE:`STRATEGY_STATE`,USER_OUTCOME:`USER_OUTCOME`,STRATEGY_LEARNING_STATE:`STRATEGY_LEARNING_STATE`}}});function areQuestionRecords(e){return isQuestionRecord(e.records[0])}function isQuestionRecord(e){return e.userAnswer!==void 0}function getCardHistoryID(e,t){return`${DocTypePrefixes.CARDRECORD}-${e}-${t}`}function parseCardHistoryID(e){let t=e.split(`-`),n=``;if(n+=t.length===3?``:`
|
|
12
12
|
given ID has incorrect number of '-' characters`,n+=t[0]===DocTypePrefixes.CARDRECORD?``:`
|
|
13
13
|
given ID does not start with ${DocTypePrefixes.CARDRECORD}`,t.length===3&&t[0]===DocTypePrefixes.CARDRECORD)return{courseID:t[1],cardID:t[2]};throw Error(`parseCardHistory Error:`+n)}function docIsDeleted(e){return e?.error===`not_found`&&e?.reason===`deleted`}var init_util=__esm({"src/core/util/index.ts"(){init_types_legacy()}}),pouchdb_setup_default,init_pouchdb_setup=__esm({"src/impl/couch/pouchdb-setup.ts"(){PouchDB.plugin(plugin$1),PouchDB.plugin(plugin),PouchDB.debug!==void 0&&PouchDB.debug.disable(),PouchDB.defaults({}),pouchdb_setup_default=PouchDB}});function getAppDataDirectory(){return ENV.LOCAL_STORAGE_PREFIX?import___vite_browser_external.join(import___vite_browser_external.homedir(),`.tuilder`,ENV.LOCAL_STORAGE_PREFIX):import___vite_browser_external.join(import___vite_browser_external.homedir(),`.tuilder`)}async function ensureAppDataDirectory(){let e=getAppDataDirectory();try{await import___vite_browser_external.promises.mkdir(e,{recursive:!0})}catch(t){if(t.code!==`EEXIST`)throw Error(`Failed to create app data directory ${e}: ${t.message}`)}return e}function getDbPath(e){return import___vite_browser_external.join(getAppDataDirectory(),e)}async function initializeDataDirectory(){await ensureAppDataDirectory(),logger.info(`PouchDB data directory initialized: ${getAppDataDirectory()}`)}var init_dataDirectory=__esm({"src/util/dataDirectory.ts"(){init_logger(),init_factory()}});function hexEncode(e){let t,n=``;for(let r=0;r<e.length;r++)t=e.charCodeAt(r).toString(16),n+=(`000`+t).slice(3);return n}function filterAllDocsByPrefix(e,t,n){let r={startkey:t,endkey:t+``,include_docs:!0};return n&&Object.assign(r,n),e.allDocs(r)}function getStartAndEndKeys(e){return{startkey:e,endkey:e+``}}function updateGuestAccountExpirationDate(e){let t=hooks.utc().add(2,`months`).toISOString(),n=`GuestAccountExpirationDate`;e.get(n).then(r=>e.put({_id:n,_rev:r._rev,date:t})).catch(()=>e.put({_id:n,date:t}))}function getLocalUserDB(e){let t=`userdb-${e}`;return typeof window>`u`?new pouchdb_setup_default(getDbPath(t),{}):new pouchdb_setup_default(t,{})}function scheduleCardReviewLocal(e,t){let n=hooks.utc();logger.info(`Scheduling for review in: ${t.time.diff(n,`h`)/24} days`),e.put({_id:DocTypePrefixes.SCHEDULED_CARD+t.time.format(REVIEW_TIME_FORMAT),cardId:t.card_id,reviewTime:t.time.toISOString(),courseId:t.course_id,scheduledAt:n.toISOString(),scheduledFor:t.scheduledFor,schedulingAgentId:t.schedulingAgentId})}async function removeScheduledCardReviewLocal(e,t){let n=await e.get(t);e.remove(n).then(e=>{e.ok&&log2(`Removed Review Doc: ${t}`)}).catch(e=>{log2(`Failed to remove Review Doc: ${t},
|
|
14
|
-
${JSON.stringify(e)}`)})}var REVIEW_TIME_FORMAT,log2,init_userDBHelpers=__esm({"src/impl/common/userDBHelpers.ts"(){init_core(),init_logger(),init_pouchdb_setup(),init_dataDirectory(),REVIEW_TIME_FORMAT=`YYYY-MM-DD--kk:mm:ss-SSS`,log2=e=>{logger.info(e)}}}),Loggable,init_Loggable=__esm({"src/util/Loggable.ts"(){Loggable=class{log(...e){console.log(`LOG-${this._className}@${new Date}:`,...e)}error(...e){console.error(`ERROR-${this._className}@${new Date}:`,...e)}}}}),UpdateQueue,init_updateQueue=__esm({"src/impl/couch/updateQueue.ts"(){init_Loggable(),init_logger(),UpdateQueue=class extends Loggable{update(e,t){return logger.debug(`Update requested on doc: ${e}`),this.pendingUpdates[e]?this.pendingUpdates[e].push(t):this.pendingUpdates[e]=[t],this.applyUpdates(e)}constructor(e,t){super(),_defineProperty(this,`_className`,`UpdateQueue`),_defineProperty(this,`pendingUpdates`,{}),_defineProperty(this,`inprogressUpdates`,{}),_defineProperty(this,`readDB`,void 0),_defineProperty(this,`writeDB`,void 0),this.readDB=e,this.writeDB=t||e,logger.debug(`UpdateQ initialized...`),this.readDB.info().then(e=>{logger.debug(`db info: ${JSON.stringify(e)}`)})}async applyUpdates(e){if(logger.debug(`Applying updates on doc: ${e}`),this.inprogressUpdates[e]){for(;this.inprogressUpdates[e];)await new Promise(e=>setTimeout(e,Math.random()*50));return this.applyUpdates(e)}else if(this.pendingUpdates[e]&&this.pendingUpdates[e].length>0){this.inprogressUpdates[e]=!0;let t=5;for(let t=0;t<5;t++)try{let t={...await this.readDB.get(e)},n=[...this.pendingUpdates[e]];for(let e of n)t=typeof e==`function`?{...t,...e(t)}:{...t,...e};if(await this.writeDB.put(t),this.pendingUpdates[e].splice(0,n.length),this.pendingUpdates[e].length===0)this.inprogressUpdates[e]=!1,delete this.inprogressUpdates[e];else return this.applyUpdates(e);return t}catch(n){if(n.name===`conflict`&&t<4)logger.warn(`Conflict on update for doc ${e}, retry #${t+1}`),await new Promise(e=>setTimeout(e,50*Math.random()));else if(n.name===`not_found`&&t===0)throw logger.warn(`Update failed for ${e} - does not exist. Throwing to caller.`),delete this.inprogressUpdates[e],n;else throw delete this.inprogressUpdates[e],this.pendingUpdates[e]&&delete this.pendingUpdates[e],logger.error(`Error on attemped update (retry ${t}): ${JSON.stringify(n)}`),n}throw Error(`UpdateQueue failed for doc ${e} after 5 retries.`)}else throw Error(`Empty Updates Queue Triggered`)}}}}),UsrCrsData,init_user_course_relDB=__esm({"src/impl/couch/user-course-relDB.ts"(){init_logger(),UsrCrsData=class{constructor(e,t){_defineProperty(this,`user`,void 0),_defineProperty(this,`_courseId`,void 0),this.user=e,this._courseId=t}async getReviewsForcast(e){let t=hooks.utc().add(e,`days`);return this.getReviewstoDate(t)}async getPendingReviews(){let e=hooks.utc();return this.getReviewstoDate(e)}async getScheduledReviewCount(){return(await this.getPendingReviews()).length}async getCourseSettings(){let e=(await this.user.getCourseRegistrationsDoc()).courses.find(e=>e.courseID===this._courseId);return e&&e.settings?e.settings:(logger.warn(`no settings found during lookup on course ${this._courseId}`),{})}updateCourseSettings(e){`updateCourseSettings`in this.user&&this.user.updateCourseSettings(this._courseId,e)}async getStrategyState(e){return this.user.getStrategyState(this._courseId,e)}async putStrategyState(e,t){return this.user.putStrategyState(this._courseId,e,t)}async deleteStrategyState(e){return this.user.deleteStrategyState(this._courseId,e)}async getReviewstoDate(e){let t=await this.user.getPendingReviews(this._courseId);return logger.debug(`Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`),t.filter(t=>{let n=hooks.utc(t.reviewTime);return e.isAfter(n)})}}}});async function GET_CACHED(e,t){return CLIENT_CACHE[e]?CLIENT_CACHE[e]:(CLIENT_CACHE[e]=t?await t(e):await GET_ITEM(e),GET_CACHED(e))}async function GET_ITEM(e){throw Error(`No implementation found for GET_CACHED(${e})`)}var CLIENT_CACHE,init_clientCache=__esm({"src/impl/couch/clientCache.ts"(){CLIENT_CACHE={}}});async function addNote55(e,t,n,r,a,o,s,c=blankCourseElo()){let l=getCourseDB(e),u=prepareNote55(e,t,n,r,a,o,s),d=`${DocTypePrefixes.DISPLAYABLE_DATA}-${v4()}`,p=await l.put({...u,_id:d}),m=NameSpacer.getDataShapeString({course:t,dataShape:n.name});if(p.ok)try{await createCards(e,m,p.id,o,c,a)}catch(e){let t=`Unknown error`;t=e instanceof Error?e.message:e&&typeof e==`object`&&`reason`in e?e.reason:e&&typeof e==`object`&&`message`in e?e.message:String(e),logger.error(`[addNote55] Failed to create cards for note ${p.id}: ${t}`),p.cardCreationFailed=!0,p.cardCreationError=t}else logger.error(`[addNote55] Error adding note. Result: ${JSON.stringify(p)}`);return p}async function createCards(e,t,n,r,a=blankCourseElo(),o){let s=await getCredentialledCourseConfig(e),c=NameSpacer.getDataShapeDescriptor(t),l=[];for(let e of s.dataShapes)e.name===t&&(l=e.questionTypes);if(l.length===0){let e=`No questionViewTypes found for datashapeID: ${t} in course config. Cards cannot be created.`;throw logger.error(e),Error(e)}for(let t of l)await createCard(t,e,c,n,r,a,o)}async function createCard(e,t,n,r,a,o=blankCourseElo(),s){let c=NameSpacer.getQuestionDescriptor(e),l=await getCredentialledCourseConfig(t);for(let u of l.questionTypes)if(u.name===e)for(let e of u.viewList)await addCard(t,n.course,[r],NameSpacer.getViewString({course:c.course,questionType:c.questionType,view:e}),o,a,s)}async function addCard(e,t,n,r,a,o,s){let c=getCourseDB(e),l=`${DocTypePrefixes.CARD}-${v4()}`,u=await c.put({_id:l,course:t,id_displayable_data:n,id_view:r,docType:`CARD`,elo:a||toCourseElo(990+Math.round(20*Math.random())),author:s});for(let t of o)logger.info(`adding tag: ${t} to card ${u.id}`),await addTagToCard(e,u.id,t,s,!1);return u}async function getCredentialledCourseConfig(e){try{let t=await getCourseDB(e).get(`CourseConfig`);return t.courseID=e,logger.info(`Returning course config: ${JSON.stringify(t)}`),t}catch(t){throw logger.error(`Error fetching config for ${e}:`,t),t}}async function addTagToCard(e,t,n,r,a=!0){let o=getTagID(n),s=getCourseDB(e),c=new CourseDB(e,async()=>BaseUser.Dummy({setupRemoteDB:()=>null,startSync:()=>{},canCreateAccount:()=>!1,canAuthenticate:()=>!1,getCurrentUsername:async()=>`DummyUser`}));try{logger.info(`Applying tag ${n} to card ${e+`-`+t}...`);let r=await s.get(o);if(r.taggedCards.includes(t))throw new AlreadyTaggedErr(`Card ${t} is already tagged with ${n}`);if(r.taggedCards.push(t),a)try{let r=(await c.getCardEloData([t]))[0];r.tags[n]={count:0,score:r.global.score},await updateCardElo(e,t,r)}catch(e){logger.error(`Failed to update ELO data for card:`,t,e)}return s.put(r)}catch(o){if(o instanceof AlreadyTaggedErr)throw o;return await createTag(e,n,r),addTagToCard(e,t,n,r,a)}}async function updateCardElo(e,t,n){if(n){let r=getCourseDB(e),a=await r.get(t);return logger.debug(`Replacing ${JSON.stringify(a.elo)} with ${JSON.stringify(n)}`),a.elo=n,r.put(a)}}function getTagID(e){let t=`TAG`.valueOf()+`-`;return e.indexOf(t)===0?e:t+e}function getCourseDB(e){let t=`coursedb-${e}`;return new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+t,createPouchDBConfig())}var AlreadyTaggedErr,init_courseAPI=__esm({"src/impl/couch/courseAPI.ts"(){init_pouchdb_setup(),init_couch(),init_factory(),init_courseDB(),init_types_legacy(),init_common(),init_logger(),AlreadyTaggedErr=class extends Error{constructor(e){super(e),this.name=`AlreadyTaggedErr`}}}}),courseLookupDBTitle,CourseLookup,init_courseLookupDB=__esm({"src/impl/couch/courseLookupDB.ts"(){var e;init_pouchdb_setup(),init_factory(),init_logger(),courseLookupDBTitle=`coursedb-lookup`,logger.debug(`COURSELOOKUP FILE RUNNING`),CourseLookup=(e=class _CourseLookup{static get _db(){if(this._dbInstance)return this._dbInstance;if(ENV.COUCHDB_SERVER_URL===`NOT_SET`||!ENV.COUCHDB_SERVER_URL)throw Error(`CourseLookup.db: COUCHDB_SERVER_URL is not set. Ensure initializeDataLayer has been called with valid configuration.`);if(ENV.COUCHDB_SERVER_PROTOCOL===`NOT_SET`||!ENV.COUCHDB_SERVER_PROTOCOL)throw Error(`CourseLookup.db: COUCHDB_SERVER_PROTOCOL is not set. Ensure initializeDataLayer has been called with valid configuration.`);let e=`${ENV.COUCHDB_SERVER_PROTOCOL}://${ENV.COUCHDB_SERVER_URL}/${courseLookupDBTitle}`,t={};ENV.COUCHDB_USERNAME&&ENV.COUCHDB_PASSWORD?(t.auth={username:ENV.COUCHDB_USERNAME,password:ENV.COUCHDB_PASSWORD},logger.info(`CourseLookup: Connecting to ${e} with authentication.`)):logger.info(`CourseLookup: Connecting to ${e} without authentication.`);try{return this._dbInstance=new pouchdb_setup_default(e,t),logger.info(`CourseLookup: Database instance created for ${courseLookupDBTitle}.`),this._dbInstance}catch(t){throw logger.error(`CourseLookup: Failed to create PouchDB instance for ${e}`,t),this._dbInstance=null,Error(`CourseLookup: Failed to initialize database connection: ${t instanceof Error?t.message:String(t)}`)}}static async add(e){return(await _CourseLookup._db.post({name:e})).id}static async addWithId(e,t,n){let r={_id:e,name:t};n&&(r.disambiguator=n),await _CourseLookup._db.put(r)}static async delete(e){let t=await _CourseLookup._db.get(e);return await _CourseLookup._db.remove(t)}static async allCourseWare(){return(await _CourseLookup._db.allDocs({include_docs:!0})).rows.map(e=>e.doc)}static async updateDisambiguator(e,t){let n=await _CourseLookup._db.get(e);return n.disambiguator=t,await _CourseLookup._db.put(n)}static async isCourse(e){try{return await _CourseLookup._db.get(e),!0}catch(e){return logger.info(`Courselookup failed:`,e),!1}}},_defineProperty(e,`_dbInstance`,null),e)}}),PipelineDebugger_exports={};__export(PipelineDebugger_exports,{buildRunReport:()=>buildRunReport,captureRun:()=>captureRun,mountPipelineDebugger:()=>mountPipelineDebugger,pipelineDebugAPI:()=>pipelineDebugAPI,registerPipelineForDebug:()=>registerPipelineForDebug});function registerPipelineForDebug(e){_activePipeline=e}function getOrigin(e){let t=e.provenance[0];if(!t)return`unknown`;let n=t.reason?.toLowerCase()||``,r=t.strategy?.toLowerCase()||``;return n.includes(`new card`)||r.includes(`elo`)?`new`:n.includes(`review`)||r.includes(`srs`)?`review`:`unknown`}function captureRun(e){let t={...e,runId:`run-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,timestamp:new Date};runHistory.unshift(t),runHistory.length>MAX_RUNS&&runHistory.pop()}function parseCardElo(e){let t=e.find(e=>e.strategy===`elo`);if(!t?.reason)return;let n=t.reason.match(/card:\s*(\d+)/);return n?parseInt(n[1],10):void 0}function buildRunReport(e,t,n,r,a,o,s,c,l,u){let d=new Set(c.map(e=>e.cardId)),p=s.map(e=>({cardId:e.cardId,courseId:e.courseId,origin:getOrigin(e),generator:e.provenance[0]?.strategyName||e.provenance[0]?.strategy,finalScore:e.score,cardElo:parseCardElo(e.provenance),provenance:e.provenance,tags:e.tags,selected:d.has(e.cardId)})),m=c.filter(e=>getOrigin(e)===`review`).length,g=c.filter(e=>getOrigin(e)===`new`).length;return{courseId:e,courseName:t,userElo:l,generatorName:n,generators:r,generatedCount:a,filters:o,hints:u,finalCount:c.length,reviewsSelected:m,newSelected:g,cards:p}}function formatProvenance(e){return e.map(e=>` ${e.action===`generated`?`🎲`:e.action===`boosted`?`⬆️`:e.action===`penalized`?`⬇️`:`➡️`} ${e.strategyName}: ${e.score.toFixed(3)} - ${e.reason}`).join(`
|
|
15
|
-
`)}function printRunSummary(e){if(console.group(`\u{1F50D} Pipeline Run: ${e.courseId} (${e.courseName||`unnamed`})`),logger.info(`Run ID: ${e.runId}`),logger.info(`Time: ${e.timestamp.toISOString()}`),logger.info(`User ELO: ${e.userElo??`unknown`}`),logger.info(`Generator: ${e.generatorName} \u2192 ${e.generatedCount} candidates`),e.generators&&e.generators.length>0){console.group(`Generator breakdown:`);for(let t of e.generators)logger.info(` ${t.name}: ${t.cardCount} cards (${t.newCount} new, ${t.reviewCount} reviews, top: ${t.topScore.toFixed(2)})`);console.groupEnd()}if(e.filters.length>0){console.group(`Filter impact:`);for(let t of e.filters)logger.info(` ${t.name}: \u2191${t.boosted} \u2193${t.penalized} =${t.passed} \u2715${t.removed}`);console.groupEnd()}logger.info(`Result: ${e.finalCount} cards selected (${e.newSelected} new, ${e.reviewsSelected} reviews)`),console.groupEnd()}function renderUI(){if(!_uiContainer)return;let e=runHistory,t=_selectedRunIndex===null?null:e[_selectedRunIndex],n=`
|
|
14
|
+
${JSON.stringify(e)}`)})}var REVIEW_TIME_FORMAT,log2,init_userDBHelpers=__esm({"src/impl/common/userDBHelpers.ts"(){init_core(),init_logger(),init_pouchdb_setup(),init_dataDirectory(),REVIEW_TIME_FORMAT=`YYYY-MM-DD--kk:mm:ss-SSS`,log2=e=>{logger.info(e)}}}),Loggable,init_Loggable=__esm({"src/util/Loggable.ts"(){Loggable=class{log(...e){console.log(`LOG-${this._className}@${new Date}:`,...e)}error(...e){console.error(`ERROR-${this._className}@${new Date}:`,...e)}}}}),UpdateQueue,init_updateQueue=__esm({"src/impl/couch/updateQueue.ts"(){init_Loggable(),init_logger(),UpdateQueue=class extends Loggable{update(e,t){return logger.debug(`Update requested on doc: ${e}`),this.pendingUpdates[e]?this.pendingUpdates[e].push(t):this.pendingUpdates[e]=[t],this.applyUpdates(e)}constructor(e,t){super(),_defineProperty(this,`_className`,`UpdateQueue`),_defineProperty(this,`pendingUpdates`,{}),_defineProperty(this,`inprogressUpdates`,{}),_defineProperty(this,`readDB`,void 0),_defineProperty(this,`writeDB`,void 0),this.readDB=e,this.writeDB=t||e,logger.debug(`UpdateQ initialized...`),this.readDB.info().then(e=>{logger.debug(`db info: ${JSON.stringify(e)}`)})}async applyUpdates(e){if(logger.debug(`Applying updates on doc: ${e}`),this.inprogressUpdates[e]){for(;this.inprogressUpdates[e];)await new Promise(e=>setTimeout(e,Math.random()*50));return this.applyUpdates(e)}else if(this.pendingUpdates[e]&&this.pendingUpdates[e].length>0){this.inprogressUpdates[e]=!0;let t=5;for(let t=0;t<5;t++)try{let t={...await this.readDB.get(e)},n=[...this.pendingUpdates[e]];for(let e of n)t=typeof e==`function`?{...t,...e(t)}:{...t,...e};if(await this.writeDB.put(t),this.pendingUpdates[e].splice(0,n.length),this.pendingUpdates[e].length===0)this.inprogressUpdates[e]=!1,delete this.inprogressUpdates[e];else return this.applyUpdates(e);return t}catch(n){if(n.name===`conflict`&&t<4)logger.warn(`Conflict on update for doc ${e}, retry #${t+1}`),await new Promise(e=>setTimeout(e,50*Math.random()));else if(n.name===`not_found`&&t===0)throw logger.warn(`Update failed for ${e} - does not exist. Throwing to caller.`),delete this.inprogressUpdates[e],n;else throw delete this.inprogressUpdates[e],this.pendingUpdates[e]&&delete this.pendingUpdates[e],logger.error(`Error on attemped update (retry ${t}): ${JSON.stringify(n)}`),n}throw Error(`UpdateQueue failed for doc ${e} after 5 retries.`)}else throw Error(`Empty Updates Queue Triggered`)}}}}),UsrCrsData,init_user_course_relDB=__esm({"src/impl/couch/user-course-relDB.ts"(){init_logger(),UsrCrsData=class{constructor(e,t){_defineProperty(this,`user`,void 0),_defineProperty(this,`_courseId`,void 0),this.user=e,this._courseId=t}async getReviewsForcast(e){let t=hooks.utc().add(e,`days`);return this.getReviewstoDate(t)}async getPendingReviews(){let e=hooks.utc();return this.getReviewstoDate(e)}async getScheduledReviewCount(){return(await this.getPendingReviews()).length}async getCourseSettings(){let e=(await this.user.getCourseRegistrationsDoc()).courses.find(e=>e.courseID===this._courseId);return e&&e.settings?e.settings:(logger.warn(`no settings found during lookup on course ${this._courseId}`),{})}updateCourseSettings(e){`updateCourseSettings`in this.user&&this.user.updateCourseSettings(this._courseId,e)}async getStrategyState(e){return this.user.getStrategyState(this._courseId,e)}async putStrategyState(e,t){return this.user.putStrategyState(this._courseId,e,t)}async deleteStrategyState(e){return this.user.deleteStrategyState(this._courseId,e)}async getReviewstoDate(e){let t=await this.user.getPendingReviews(this._courseId);return logger.debug(`Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`),t.filter(t=>{let n=hooks.utc(t.reviewTime);return e.isAfter(n)})}}}});async function GET_CACHED(e,t){return CLIENT_CACHE[e]?CLIENT_CACHE[e]:(CLIENT_CACHE[e]=t?await t(e):await GET_ITEM(e),GET_CACHED(e))}async function GET_ITEM(e){throw Error(`No implementation found for GET_CACHED(${e})`)}var CLIENT_CACHE,init_clientCache=__esm({"src/impl/couch/clientCache.ts"(){CLIENT_CACHE={}}});async function addNote55(e,t,n,r,a,o,s,c=blankCourseElo()){let l=getCourseDB(e),u=prepareNote55(e,t,n,r,a,o,s),d=`${DocTypePrefixes.DISPLAYABLE_DATA}-${v4()}`,p=await l.put({...u,_id:d}),m=NameSpacer.getDataShapeString({course:t,dataShape:n.name});if(p.ok)try{await createCards(e,m,p.id,o,c,a)}catch(e){let t=`Unknown error`;t=e instanceof Error?e.message:e&&typeof e==`object`&&`reason`in e?e.reason:e&&typeof e==`object`&&`message`in e?e.message:String(e),logger.error(`[addNote55] Failed to create cards for note ${p.id}: ${t}`),p.cardCreationFailed=!0,p.cardCreationError=t}else logger.error(`[addNote55] Error adding note. Result: ${JSON.stringify(p)}`);return p}async function createCards(e,t,n,r,a=blankCourseElo(),o){let s=await getCredentialledCourseConfig(e),c=NameSpacer.getDataShapeDescriptor(t),l=[];for(let e of s.dataShapes)e.name===t&&(l=e.questionTypes);if(l.length===0){let e=`No questionViewTypes found for datashapeID: ${t} in course config. Cards cannot be created.`;throw logger.error(e),Error(e)}for(let t of l)await createCard(t,e,c,n,r,a,o)}async function createCard(e,t,n,r,a,o=blankCourseElo(),s){let c=NameSpacer.getQuestionDescriptor(e),l=await getCredentialledCourseConfig(t);for(let u of l.questionTypes)if(u.name===e)for(let e of u.viewList)await addCard(t,n.course,[r],NameSpacer.getViewString({course:c.course,questionType:c.questionType,view:e}),o,a,s)}async function addCard(e,t,n,r,a,o,s){let c=getCourseDB(e),l=`${DocTypePrefixes.CARD}-${v4()}`,u=await c.put({_id:l,course:t,id_displayable_data:n,id_view:r,docType:`CARD`,elo:a||toCourseElo(990+Math.round(20*Math.random())),author:s});for(let t of o)logger.info(`adding tag: ${t} to card ${u.id}`),await addTagToCard(e,u.id,t,s,!1);return u}async function getCredentialledCourseConfig(e){try{let t=await getCourseDB(e).get(`CourseConfig`);return t.courseID=e,logger.info(`Returning course config: ${JSON.stringify(t)}`),t}catch(t){throw logger.error(`Error fetching config for ${e}:`,t),t}}async function addTagToCard(e,t,n,r,a=!0){let o=getTagID(n),s=getCourseDB(e),c=new CourseDB(e,async()=>BaseUser.Dummy({setupRemoteDB:()=>null,startSync:()=>{},canCreateAccount:()=>!1,canAuthenticate:()=>!1,getCurrentUsername:async()=>`DummyUser`}));try{logger.info(`Applying tag ${n} to card ${e+`-`+t}...`);let r=await s.get(o);if(r.taggedCards.includes(t))throw new AlreadyTaggedErr(`Card ${t} is already tagged with ${n}`);if(r.taggedCards.push(t),a)try{let r=(await c.getCardEloData([t]))[0];r.tags[n]={count:0,score:r.global.score},await updateCardElo(e,t,r)}catch(e){logger.error(`Failed to update ELO data for card:`,t,e)}return s.put(r)}catch(o){if(o instanceof AlreadyTaggedErr)throw o;return await createTag(e,n,r),addTagToCard(e,t,n,r,a)}}async function updateCardElo(e,t,n){if(n){let r=getCourseDB(e),a=await r.get(t);return logger.debug(`Replacing ${JSON.stringify(a.elo)} with ${JSON.stringify(n)}`),a.elo=n,r.put(a)}}function getTagID(e){let t=`TAG`.valueOf()+`-`;return e.indexOf(t)===0?e:t+e}function getCourseDB(e){let t=`coursedb-${e}`;return new pouchdb_setup_default(ENV.COUCHDB_SERVER_PROTOCOL+`://`+ENV.COUCHDB_SERVER_URL+t,createPouchDBConfig())}var AlreadyTaggedErr,init_courseAPI=__esm({"src/impl/couch/courseAPI.ts"(){init_pouchdb_setup(),init_couch(),init_factory(),init_courseDB(),init_types_legacy(),init_common(),init_logger(),AlreadyTaggedErr=class extends Error{constructor(e){super(e),this.name=`AlreadyTaggedErr`}}}}),courseLookupDBTitle,CourseLookup,init_courseLookupDB=__esm({"src/impl/couch/courseLookupDB.ts"(){var e;init_pouchdb_setup(),init_factory(),init_logger(),courseLookupDBTitle=`coursedb-lookup`,logger.debug(`COURSELOOKUP FILE RUNNING`),CourseLookup=(e=class _CourseLookup{static get _db(){if(this._dbInstance)return this._dbInstance;if(ENV.COUCHDB_SERVER_URL===`NOT_SET`||!ENV.COUCHDB_SERVER_URL)throw Error(`CourseLookup.db: COUCHDB_SERVER_URL is not set. Ensure initializeDataLayer has been called with valid configuration.`);if(ENV.COUCHDB_SERVER_PROTOCOL===`NOT_SET`||!ENV.COUCHDB_SERVER_PROTOCOL)throw Error(`CourseLookup.db: COUCHDB_SERVER_PROTOCOL is not set. Ensure initializeDataLayer has been called with valid configuration.`);let e=`${ENV.COUCHDB_SERVER_PROTOCOL}://${ENV.COUCHDB_SERVER_URL}/${courseLookupDBTitle}`,t={};ENV.COUCHDB_USERNAME&&ENV.COUCHDB_PASSWORD?(t.auth={username:ENV.COUCHDB_USERNAME,password:ENV.COUCHDB_PASSWORD},logger.info(`CourseLookup: Connecting to ${e} with authentication.`)):logger.info(`CourseLookup: Connecting to ${e} without authentication.`);try{return this._dbInstance=new pouchdb_setup_default(e,t),logger.info(`CourseLookup: Database instance created for ${courseLookupDBTitle}.`),this._dbInstance}catch(t){throw logger.error(`CourseLookup: Failed to create PouchDB instance for ${e}`,t),this._dbInstance=null,Error(`CourseLookup: Failed to initialize database connection: ${t instanceof Error?t.message:String(t)}`)}}static async add(e){return(await _CourseLookup._db.post({name:e})).id}static async addWithId(e,t,n){let r={_id:e,name:t};n&&(r.disambiguator=n),await _CourseLookup._db.put(r)}static async delete(e){let t=await _CourseLookup._db.get(e);return await _CourseLookup._db.remove(t)}static async allCourseWare(){return(await _CourseLookup._db.allDocs({include_docs:!0})).rows.map(e=>e.doc)}static async updateDisambiguator(e,t){let n=await _CourseLookup._db.get(e);return n.disambiguator=t,await _CourseLookup._db.put(n)}static async isCourse(e){try{return await _CourseLookup._db.get(e),!0}catch(e){return logger.info(`Courselookup failed:`,e),!1}}},_defineProperty(e,`_dbInstance`,null),e)}}),PipelineDebugger_exports={};__export(PipelineDebugger_exports,{buildRunReport:()=>buildRunReport,captureRun:()=>captureRun,clearRunHistory:()=>clearRunHistory,mountPipelineDebugger:()=>mountPipelineDebugger,pipelineDebugAPI:()=>pipelineDebugAPI,registerPipelineForDebug:()=>registerPipelineForDebug});function registerPipelineForDebug(e){_activePipeline=e}function clearRunHistory(){runHistory.length=0}function getOrigin(e){let t=e.provenance[0];if(!t)return`unknown`;let n=t.reason?.toLowerCase()||``,r=t.strategy?.toLowerCase()||``;return n.includes(`new card`)||r.includes(`elo`)?`new`:n.includes(`review`)||r.includes(`srs`)?`review`:`unknown`}function captureRun(e){let t={...e,runId:`run-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,timestamp:new Date};runHistory.unshift(t),runHistory.length>MAX_RUNS&&runHistory.pop()}function parseCardElo(e){let t=e.find(e=>e.strategy===`elo`);if(!t?.reason)return;let n=t.reason.match(/card:\s*(\d+)/);return n?parseInt(n[1],10):void 0}function buildRunReport(e,t,n,r,a,o,s,c,l,u){let d=new Set(c.map(e=>e.cardId)),toReport=e=>({cardId:e.cardId,courseId:e.courseId,origin:getOrigin(e),generator:e.provenance[0]?.strategyName||e.provenance[0]?.strategy,finalScore:e.score,cardElo:parseCardElo(e.provenance),provenance:e.provenance,tags:e.tags,selected:d.has(e.cardId)}),p=[],m=[],g=[],_=0;for(let e of s)d.has(e.cardId)?p.push(toReport(e)):_<DISCARDED_KEEP_TOP?(m.push(toReport(e)),_++):g.push(e);let v=[...p,...m],y;if(g.length>0){let e=1/0,t=-1/0,n=1/0,r=-1/0,a=!1;for(let o of g){o.score<e&&(e=o.score),o.score>t&&(t=o.score);let s=parseCardElo(o.provenance);s!==void 0&&(a=!0,s<n&&(n=s),s>r&&(r=s))}let o=a?`, ELO ${n}\u2013${r}`:``;y={count:g.length,scoreRange:[e,t],eloRange:a?[n,r]:void 0,note:`${g.length} additional candidate(s) scored below the top ${DISCARDED_KEEP_TOP} near-misses and were not retained (score ${e.toExponential(2)}\u2013${t.toExponential(2)}${o}). Likely ELO-window pull remnants filtered out by hierarchy/lesson/priority gates.`}}let b=c.filter(e=>getOrigin(e)===`review`).length,x=c.filter(e=>getOrigin(e)===`new`).length;return{courseId:e,courseName:t,userElo:l,generatorName:n,generators:r,generatedCount:a,filters:o,hints:u,finalCount:c.length,reviewsSelected:b,newSelected:x,cards:v,discardedTail:y}}function formatProvenance(e){return e.map(e=>` ${e.action===`generated`?`🎲`:e.action===`boosted`?`⬆️`:e.action===`penalized`?`⬇️`:`➡️`} ${e.strategyName}: ${e.score.toFixed(3)} - ${e.reason}`).join(`
|
|
15
|
+
`)}function printRunSummary(e){if(console.group(`\u{1F50D} Pipeline Run: ${e.courseId} (${e.courseName||`unnamed`})`),logger.info(`Run ID: ${e.runId}`),logger.info(`Time: ${e.timestamp.toISOString()}`),logger.info(`User ELO: ${e.userElo??`unknown`}`),logger.info(`Generator: ${e.generatorName} \u2192 ${e.generatedCount} candidates`),e.generators&&e.generators.length>0){console.group(`Generator breakdown:`);for(let t of e.generators)logger.info(` ${t.name}: ${t.cardCount} cards (${t.newCount} new, ${t.reviewCount} reviews, top: ${t.topScore.toFixed(2)})`);console.groupEnd()}if(e.filters.length>0){console.group(`Filter impact:`);for(let t of e.filters)logger.info(` ${t.name}: \u2191${t.boosted} \u2193${t.penalized} =${t.passed} \u2715${t.removed}`);console.groupEnd()}logger.info(`Result: ${e.finalCount} cards selected (${e.newSelected} new, ${e.reviewsSelected} reviews)`),console.groupEnd()}function escapeHtml(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`)}function escapeAttr(e){return escapeHtml(e).replace(/"/g,`"`)}function copyTextToClipboard(e,t){let done=()=>{if(!t)return;let e=t.textContent??`Copy`;t.textContent=`Copied!`,t.classList.add(`copied`),setTimeout(()=>{t.textContent=e,t.classList.remove(`copied`)},1200)},fallback=()=>{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.opacity=`0`,document.body.appendChild(t),t.select();try{document.execCommand(`copy`)}catch(e){logger.warn(`[Pipeline Debug] Copy failed: ${e}`)}document.body.removeChild(t),done()};navigator.clipboard?.writeText?navigator.clipboard.writeText(e).then(done).catch(fallback):fallback()}function renderUI(){if(!_uiContainer)return;let e=runHistory,t=_selectedRunIndex===null?null:e[_selectedRunIndex],n=`
|
|
16
16
|
#sk-pipeline-debugger {
|
|
17
17
|
position: fixed;
|
|
18
18
|
top: 0;
|
|
@@ -66,17 +66,26 @@ ${JSON.stringify(e)}`)})}var REVIEW_TIME_FORMAT,log2,init_userDBHelpers=__esm({"
|
|
|
66
66
|
#sk-pipeline-debugger .close-btn { background: #dc3545; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; }
|
|
67
67
|
#sk-pipeline-debugger .search-box { margin-bottom: 1rem; width: 100%; padding: 0.5rem; border: 1px solid #ced4da; border-radius: 4px; }
|
|
68
68
|
#sk-pipeline-debugger .provenance { font-size: 12px; color: #666; margin-top: 0.25rem; white-space: pre-wrap; font-family: monospace; background: #f8f9fa; padding: 0.5rem; border-radius: 4px; }
|
|
69
|
+
#sk-pipeline-debugger .run-label { display: inline-block; margin-top: 0.25rem; padding: 0.1rem 0.4rem; background: #fff3cd; color: #664d03; border-radius: 3px; font-family: monospace; font-size: 11px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
|
|
70
|
+
#sk-pipeline-debugger .label-banner { display: inline-block; padding: 0.25rem 0.6rem; background: #fff3cd; color: #664d03; border-radius: 4px; font-family: monospace; font-size: 13px; margin: 0 0 0.75rem 0; }
|
|
71
|
+
#sk-pipeline-debugger .copy-btn { background: #0d6efd; color: white; border: none; padding: 0.25rem 0.6rem; border-radius: 3px; cursor: pointer; font-size: 12px; margin-left: 0.5rem; }
|
|
72
|
+
#sk-pipeline-debugger .copy-btn:hover { background: #0b5ed7; }
|
|
73
|
+
#sk-pipeline-debugger .copy-btn.copied { background: #198754; }
|
|
74
|
+
#sk-pipeline-debugger .section-head { display: flex; align-items: center; justify-content: space-between; margin-top: 1rem; }
|
|
75
|
+
#sk-pipeline-debugger .section-head h3 { margin: 0; }
|
|
69
76
|
`,r=e.length===0?`<div style="padding: 1rem;">No runs captured yet.</div>`:e.map((e,t)=>`
|
|
70
77
|
<div class="run-item ${t===_selectedRunIndex?`active`:``}" onclick="window.skuilder.pipeline._selectRun(${t})">
|
|
71
78
|
<strong>${e.timestamp.toLocaleTimeString()}</strong><br/>
|
|
72
79
|
<small>${e.courseName||e.courseId.slice(0,8)}</small><br/>
|
|
73
80
|
<small>${e.finalCount} cards selected</small>
|
|
81
|
+
${e.hints?._label?`<br/><span class="run-label" title="${escapeAttr(e.hints._label)}">${escapeHtml(e.hints._label)}</span>`:``}
|
|
74
82
|
</div>
|
|
75
|
-
`).join(``),a=`<div style="color: #6c757d; text-align: center; margin-top: 5rem;">Select a run to see details</div>`;if(t){let e=t.cards.filter(e=>!_cardSearchQuery||e.cardId.toLowerCase().includes(_cardSearchQuery.toLowerCase()))
|
|
83
|
+
`).join(``),a=`<div style="color: #6c757d; text-align: center; margin-top: 5rem;">Select a run to see details</div>`;if(t){let e=t.cards.filter(e=>!_cardSearchQuery||e.cardId.toLowerCase().includes(_cardSearchQuery.toLowerCase())),n=t.hints?._label??`(no label)`;a=`
|
|
76
84
|
<h2>Run: ${t.runId}</h2>
|
|
85
|
+
<div class="label-banner" title="${escapeAttr(n)}">${escapeHtml(n)}</div>
|
|
77
86
|
<p>
|
|
78
|
-
<strong>Time:</strong> ${t.timestamp.toLocaleString()} |
|
|
79
|
-
<strong>Course:</strong> ${t.courseName||t.courseId} |
|
|
87
|
+
<strong>Time:</strong> ${t.timestamp.toLocaleString()} |
|
|
88
|
+
<strong>Course:</strong> ${t.courseName||t.courseId} |
|
|
80
89
|
<strong>User ELO:</strong> ${t.userElo??`unknown`}
|
|
81
90
|
</p>
|
|
82
91
|
|
|
@@ -89,7 +98,10 @@ ${JSON.stringify(e)}`)})}var REVIEW_TIME_FORMAT,log2,init_userDBHelpers=__esm({"
|
|
|
89
98
|
</table>
|
|
90
99
|
|
|
91
100
|
${t.hints?`
|
|
92
|
-
<
|
|
101
|
+
<div class="section-head">
|
|
102
|
+
<h3>Ephemeral Hints</h3>
|
|
103
|
+
<button class="copy-btn" onclick="window.skuilder.pipeline._copyConfig('${t.runId}', this)">Copy config</button>
|
|
104
|
+
</div>
|
|
93
105
|
<table>
|
|
94
106
|
${t.hints._label?`<tr><th>Label</th><td>${t.hints._label}</td></tr>`:``}
|
|
95
107
|
${t.hints.boostTags?`<tr><th>Boost Tags</th><td><pre style="margin:0">${JSON.stringify(t.hints.boostTags,null,2)}</pre></td></tr>`:``}
|
|
@@ -111,7 +123,10 @@ ${JSON.stringify(e)}`)})}var REVIEW_TIME_FORMAT,log2,init_userDBHelpers=__esm({"
|
|
|
111
123
|
</tbody>
|
|
112
124
|
</table>
|
|
113
125
|
|
|
114
|
-
<
|
|
126
|
+
<div class="section-head">
|
|
127
|
+
<h3>Cards (${t.finalCount} selected / ${t.cards.length} total)</h3>
|
|
128
|
+
<button class="copy-btn" onclick="window.skuilder.pipeline._copyResults('${t.runId}', this)">Copy results</button>
|
|
129
|
+
</div>
|
|
115
130
|
<input type="text" class="search-box" placeholder="Search Card ID..." value="${_cardSearchQuery}" oninput="window.skuilder.pipeline._setSearch(this.value)">
|
|
116
131
|
|
|
117
132
|
<table>
|
|
@@ -190,6 +205,13 @@ ${JSON.stringify(e)}`)})}var REVIEW_TIME_FORMAT,log2,init_userDBHelpers=__esm({"
|
|
|
190
205
|
#sk-pipeline-debugger .close-btn { background: #dc3545; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; }
|
|
191
206
|
#sk-pipeline-debugger .search-box { margin-bottom: 1rem; width: 100%; padding: 0.5rem; border: 1px solid #ced4da; border-radius: 4px; }
|
|
192
207
|
#sk-pipeline-debugger .provenance { font-size: 12px; color: #666; margin-top: 0.25rem; white-space: pre-wrap; font-family: monospace; background: #f8f9fa; padding: 0.5rem; border-radius: 4px; }
|
|
208
|
+
#sk-pipeline-debugger .run-label { display: inline-block; margin-top: 0.25rem; padding: 0.1rem 0.4rem; background: #fff3cd; color: #664d03; border-radius: 3px; font-family: monospace; font-size: 11px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
|
|
209
|
+
#sk-pipeline-debugger .label-banner { display: inline-block; padding: 0.25rem 0.6rem; background: #fff3cd; color: #664d03; border-radius: 4px; font-family: monospace; font-size: 13px; margin: 0 0 0.75rem 0; }
|
|
210
|
+
#sk-pipeline-debugger .copy-btn { background: #0d6efd; color: white; border: none; padding: 0.25rem 0.6rem; border-radius: 3px; cursor: pointer; font-size: 12px; margin-left: 0.5rem; }
|
|
211
|
+
#sk-pipeline-debugger .copy-btn:hover { background: #0b5ed7; }
|
|
212
|
+
#sk-pipeline-debugger .copy-btn.copied { background: #198754; }
|
|
213
|
+
#sk-pipeline-debugger .section-head { display: flex; align-items: center; justify-content: space-between; margin-top: 1rem; }
|
|
214
|
+
#sk-pipeline-debugger .section-head h3 { margin: 0; }
|
|
193
215
|
</style>
|
|
194
216
|
<header>
|
|
195
217
|
<strong>Pipeline Debugger</strong>
|
|
@@ -199,7 +221,7 @@ ${JSON.stringify(e)}`)})}var REVIEW_TIME_FORMAT,log2,init_userDBHelpers=__esm({"
|
|
|
199
221
|
<div class="sidebar">${r}</div>
|
|
200
222
|
<div class="main-content">${a}</div>
|
|
201
223
|
</div>
|
|
202
|
-
`}function mountPipelineDebugger(){if(typeof window>`u`)return;let e=window;e.skuilder=e.skuilder||{},e.skuilder.pipeline=pipelineDebugAPI}var _activePipeline,MAX_RUNS,runHistory,_uiContainer,_selectedRunIndex,_cardSearchQuery,pipelineDebugAPI,init_PipelineDebugger=__esm({"src/core/navigators/PipelineDebugger.ts"(){init_navigators(),init_logger(),_activePipeline=null,MAX_RUNS=10,runHistory=[],_uiContainer=null,_selectedRunIndex=null,_cardSearchQuery=``,pipelineDebugAPI={get runs(){return[...runHistory]},showRun(e=0){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}let t;if(typeof e==`number`){if(t=runHistory[e],!t){logger.info(`[Pipeline Debug] No run found at index ${e}. History length: ${runHistory.length}`);return}}else if(t=runHistory.find(t=>t.runId.endsWith(e)),!t){logger.info(`[Pipeline Debug] No run found matching ID '${e}'.`);return}printRunSummary(t)},showLastRun(){this.showRun(0)},showCard(e){for(let t of runHistory){let n=t.cards.find(t=>t.cardId===e);if(n){console.group(`\u{1F3B4} Card: ${e}`),logger.info(`Course: ${n.courseId}`),logger.info(`Origin: ${n.origin}`),logger.info(`Card ELO: ${n.cardElo??`unknown`} | User ELO: ${t.userElo??`unknown`}`),logger.info(`Final score: ${n.finalScore.toFixed(3)}`),logger.info(`Selected: ${n.selected?`Yes ✅`:`No ❌`}`),n.tags&&n.tags.length>0&&logger.info(`Tags (${n.tags.length}): ${n.tags.join(`, `)}`),logger.info(`Provenance:`),logger.info(formatProvenance(n.provenance)),console.groupEnd();return}}logger.info(`[Pipeline Debug] Card '${e}' not found in recent runs.`)},explainReviews(){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}console.group(`📋 Review Selection Analysis`);for(let e of runHistory){console.group(`Run: ${e.courseId} @ ${e.timestamp.toLocaleTimeString()}`);let t=e.cards.filter(e=>e.origin===`review`),n=t.filter(e=>e.selected);if(t.length===0)logger.info(`❌ No reviews were generated. Check SRS logs for why.`);else if(n.length===0){logger.info(`\u26A0\uFE0F ${t.length} reviews generated but none selected.`),logger.info(`Possible reasons:`);let n=Math.max(...e.cards.filter(e=>e.origin===`new`&&e.selected).map(e=>e.finalScore),0),r=Math.max(...t.map(e=>e.finalScore),0);r<n&&logger.info(` - New cards scored higher (top new: ${n.toFixed(2)}, top review: ${r.toFixed(2)})`);let a=t.sort((e,t)=>t.finalScore-e.finalScore)[0];a&&(logger.info(` - Top review score: ${a.finalScore.toFixed(3)}`),logger.info(` - Its provenance:`),logger.info(formatProvenance(a.provenance)))}else{logger.info(`\u2705 ${n.length}/${t.length} reviews selected.`),logger.info(`Top selected review:`);let e=n.sort((e,t)=>t.finalScore-e.finalScore)[0];logger.info(formatProvenance(e.provenance))}console.groupEnd()}console.groupEnd()},showPrescribed(e){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}let t=runHistory[0],n=t.cards.filter(e=>e.provenance.some(e=>e.strategy===`prescribed`));if(console.group(`\u{1F9ED} Prescribed Debug (${t.courseId})`),n.length===0){logger.info(`No prescribed-generated cards were present in the most recent run.`),console.groupEnd();return}let r=n.map(e=>{let t=e.provenance.find(e=>e.strategy===`prescribed`)?.reason??``,n=t.match(/group=([^;]+)/)?.[1]??`unknown`,r=t.match(/mode=([^;]+)/)?.[1]??`unknown`,a=t.match(/blocked=([^;]+)/)?.[1]??`unknown`,o=t.match(/blockedTargets=([^;]+)/)?.[1]??`none`,s=t.match(/supportCard=([^;]+)/)?.[1]??`none`,c=t.match(/supportTags=([^;]+)/)?.[1]??`none`,l=t.match(/multiplier=([^;]+)/)?.[1]??`unknown`;return{group:n,mode:r,supportSource:r===`discovered-support`?`discovered`:r===`support`?`authored`:`n/a`,cardId:e.cardId,selected:e.selected?`yes`:`no`,finalScore:e.finalScore.toFixed(3),blocked:a,blockedTargets:o,supportCard:s,supportTags:c,multiplier:l}}).filter(t=>!e||t.group===e).sort((e,t)=>Number(t.finalScore)-Number(e.finalScore));if(r.length===0){logger.info(`[Pipeline Debug] No prescribed cards matched group '${e}' in the most recent run.`),console.groupEnd();return}console.table(r);let a=r.filter(e=>e.selected===`yes`),o=new Set,s=new Set,c=new Set,l=new Set;for(let e of r)e.blockedTargets&&e.blockedTargets!==`none`&&e.blockedTargets.split(`|`).filter(Boolean).forEach(e=>o.add(e)),e.supportTags&&e.supportTags!==`none`&&e.supportTags.split(`|`).filter(Boolean).forEach(e=>s.add(e)),e.supportCard&&e.supportCard!==`none`&&(e.supportSource===`discovered`?l.add(e.supportCard):e.supportSource===`authored`&&c.add(e.supportCard));logger.info(`Prescribed cards in run: ${r.length}`),logger.info(`Selected prescribed cards: ${a.length}`),logger.info(`Blocked prescribed targets referenced: ${o.size>0?[...o].join(`, `):`none`}`),logger.info(`Resolved support tags referenced: ${s.size>0?[...s].join(`, `):`none`}`),logger.info(`Authored support cards emitted: ${c.size>0?[...c].join(`, `):`none`}`),logger.info(`Discovered support cards emitted: ${l.size>0?[...l].join(`, `):`none`}`),console.groupEnd()},listRuns(){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}console.table(runHistory.map(e=>({id:e.runId.slice(-8),time:e.timestamp.toLocaleTimeString(),course:e.courseName||e.courseId.slice(0,8),generated:e.generatedCount,selected:e.finalCount,new:e.newSelected,reviews:e.reviewsSelected})))},export(){let e=JSON.stringify(runHistory,null,2);return logger.info(`[Pipeline Debug] Run history exported. Copy the returned string or use:`),logger.info(` copy(window.skuilder.pipeline.export())`),e},clear(){runHistory.length=0,logger.info(`[Pipeline Debug] Run history cleared.`)},showRegistry(){let e=getRegisteredNavigatorNames();if(e.length===0){logger.info(`[Pipeline Debug] Navigator registry is empty.`);return}console.group(`📦 Navigator Registry`),console.table(e.map(e=>{let t=getRegisteredNavigatorRole(e),n=NavigatorRoles[e];return{name:e,role:n||t||`⚠️ NONE`,source:n?`built-in`:t?`consumer`:`unclassified`,isGenerator:isGenerator(e),isFilter:isFilter(e)}})),console.groupEnd()},showStrategies(){if(this.showRegistry(),runHistory.length===0){logger.info(`[Pipeline Debug] No pipeline runs captured yet — cannot show strategy doc mapping.`);return}let e=runHistory[0];if(console.group(`🔌 Pipeline Strategy Mapping (last run)`),logger.info(`Generator: ${e.generatorName}`),e.generators&&e.generators.length>0)for(let t of e.generators)logger.info(` \u{1F4E5} ${t.name}: ${t.cardCount} cards (${t.newCount} new, ${t.reviewCount} reviews)`);if(e.filters.length>0){logger.info(`Filters:`);for(let t of e.filters)logger.info(` \u{1F538} ${t.name}: \u2191${t.boosted} \u2193${t.penalized} =${t.passed} \u2715${t.removed}`)}else logger.info(`Filters: (none)`);console.groupEnd()},async diagnoseCardSpace(e){return _activePipeline?_activePipeline.diagnoseCardSpace({threshold:e}):(logger.info(`[Pipeline Debug] No active pipeline. Run a session first.`),null)},async showTagElo(e){if(!_activePipeline){logger.info(`[Pipeline Debug] No active pipeline. Run a session first.`);return}let t=await _activePipeline.getTagEloStatus(e),n=Object.entries(t).sort(([e],[t])=>e.localeCompare(t));if(n.length===0){logger.info(`[Pipeline Debug] No tag ELO data found${e?` for pattern: ${e}`:``}.`);return}console.table(Object.fromEntries(n.map(([e,t])=>[e,{score:Math.round(t.score),count:t.count}])))},ui(){if(_uiContainer){document.body.removeChild(_uiContainer),_uiContainer=null;return}_uiContainer=document.createElement(`div`),_uiContainer.id=`sk-pipeline-debugger`,document.body.appendChild(_uiContainer),_selectedRunIndex===null&&runHistory.length>0&&(_selectedRunIndex=0),renderUI()},_selectRun(e){_selectedRunIndex=e,renderUI()},_setSearch(e){_cardSearchQuery=e,renderUI()},help(){logger.info(`
|
|
224
|
+
`}function mountPipelineDebugger(){if(typeof window>`u`)return;let e=window;e.skuilder=e.skuilder||{},e.skuilder.pipeline=pipelineDebugAPI}var _activePipeline,MAX_RUNS,runHistory,DISCARDED_KEEP_TOP,_uiContainer,_selectedRunIndex,_cardSearchQuery,pipelineDebugAPI,init_PipelineDebugger=__esm({"src/core/navigators/PipelineDebugger.ts"(){init_navigators(),init_logger(),_activePipeline=null,MAX_RUNS=10,runHistory=[],DISCARDED_KEEP_TOP=25,_uiContainer=null,_selectedRunIndex=null,_cardSearchQuery=``,pipelineDebugAPI={get runs(){return[...runHistory]},showRun(e=0){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}let t;if(typeof e==`number`){if(t=runHistory[e],!t){logger.info(`[Pipeline Debug] No run found at index ${e}. History length: ${runHistory.length}`);return}}else if(t=runHistory.find(t=>t.runId.endsWith(e)),!t){logger.info(`[Pipeline Debug] No run found matching ID '${e}'.`);return}printRunSummary(t)},showLastRun(){this.showRun(0)},showCard(e){for(let t of runHistory){let n=t.cards.find(t=>t.cardId===e);if(n){console.group(`\u{1F3B4} Card: ${e}`),logger.info(`Course: ${n.courseId}`),logger.info(`Origin: ${n.origin}`),logger.info(`Card ELO: ${n.cardElo??`unknown`} | User ELO: ${t.userElo??`unknown`}`),logger.info(`Final score: ${n.finalScore.toFixed(3)}`),logger.info(`Selected: ${n.selected?`Yes ✅`:`No ❌`}`),n.tags&&n.tags.length>0&&logger.info(`Tags (${n.tags.length}): ${n.tags.join(`, `)}`),logger.info(`Provenance:`),logger.info(formatProvenance(n.provenance)),console.groupEnd();return}}let t=runHistory.filter(e=>e.discardedTail&&e.discardedTail.count>0);t.length>0?logger.info(`[Pipeline Debug] Card '${e}' not found in retained cards. ${t.length} run(s) have discarded tails that were not retained \u2014 the card may have been a low-score candidate. See run.discardedTail for ranges.`):logger.info(`[Pipeline Debug] Card '${e}' not found in recent runs.`)},explainReviews(){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}console.group(`📋 Review Selection Analysis`);for(let e of runHistory){console.group(`Run: ${e.courseId} @ ${e.timestamp.toLocaleTimeString()}`);let t=e.cards.filter(e=>e.origin===`review`),n=t.filter(e=>e.selected);if(t.length===0)logger.info(`❌ No reviews were generated. Check SRS logs for why.`);else if(n.length===0){logger.info(`\u26A0\uFE0F ${t.length} reviews generated but none selected.`),logger.info(`Possible reasons:`);let n=Math.max(...e.cards.filter(e=>e.origin===`new`&&e.selected).map(e=>e.finalScore),0),r=Math.max(...t.map(e=>e.finalScore),0);r<n&&logger.info(` - New cards scored higher (top new: ${n.toFixed(2)}, top review: ${r.toFixed(2)})`);let a=t.sort((e,t)=>t.finalScore-e.finalScore)[0];a&&(logger.info(` - Top review score: ${a.finalScore.toFixed(3)}`),logger.info(` - Its provenance:`),logger.info(formatProvenance(a.provenance)))}else{logger.info(`\u2705 ${n.length}/${t.length} reviews selected.`),logger.info(`Top selected review:`);let e=n.sort((e,t)=>t.finalScore-e.finalScore)[0];logger.info(formatProvenance(e.provenance))}console.groupEnd()}console.groupEnd()},showPrescribed(e){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}let t=runHistory[0],n=t.cards.filter(e=>e.provenance.some(e=>e.strategy===`prescribed`));if(console.group(`\u{1F9ED} Prescribed Debug (${t.courseId})`),n.length===0){logger.info(`No prescribed-generated cards were present in the most recent run.`),console.groupEnd();return}let r=n.map(e=>{let t=e.provenance.find(e=>e.strategy===`prescribed`)?.reason??``,n=t.match(/group=([^;]+)/)?.[1]??`unknown`,r=t.match(/mode=([^;]+)/)?.[1]??`unknown`,a=t.match(/blocked=([^;]+)/)?.[1]??`unknown`,o=t.match(/blockedTargets=([^;]+)/)?.[1]??`none`,s=t.match(/supportCard=([^;]+)/)?.[1]??`none`,c=t.match(/supportTags=([^;]+)/)?.[1]??`none`,l=t.match(/multiplier=([^;]+)/)?.[1]??`unknown`;return{group:n,mode:r,supportSource:r===`discovered-support`?`discovered`:r===`support`?`authored`:`n/a`,cardId:e.cardId,selected:e.selected?`yes`:`no`,finalScore:e.finalScore.toFixed(3),blocked:a,blockedTargets:o,supportCard:s,supportTags:c,multiplier:l}}).filter(t=>!e||t.group===e).sort((e,t)=>Number(t.finalScore)-Number(e.finalScore));if(r.length===0){logger.info(`[Pipeline Debug] No prescribed cards matched group '${e}' in the most recent run.`),console.groupEnd();return}console.table(r);let a=r.filter(e=>e.selected===`yes`),o=new Set,s=new Set,c=new Set,l=new Set;for(let e of r)e.blockedTargets&&e.blockedTargets!==`none`&&e.blockedTargets.split(`|`).filter(Boolean).forEach(e=>o.add(e)),e.supportTags&&e.supportTags!==`none`&&e.supportTags.split(`|`).filter(Boolean).forEach(e=>s.add(e)),e.supportCard&&e.supportCard!==`none`&&(e.supportSource===`discovered`?l.add(e.supportCard):e.supportSource===`authored`&&c.add(e.supportCard));logger.info(`Prescribed cards in run: ${r.length}`),logger.info(`Selected prescribed cards: ${a.length}`),logger.info(`Blocked prescribed targets referenced: ${o.size>0?[...o].join(`, `):`none`}`),logger.info(`Resolved support tags referenced: ${s.size>0?[...s].join(`, `):`none`}`),logger.info(`Authored support cards emitted: ${c.size>0?[...c].join(`, `):`none`}`),logger.info(`Discovered support cards emitted: ${l.size>0?[...l].join(`, `):`none`}`),console.groupEnd()},listRuns(){if(runHistory.length===0){logger.info(`[Pipeline Debug] No runs captured yet.`);return}console.table(runHistory.map(e=>({id:e.runId.slice(-8),time:e.timestamp.toLocaleTimeString(),course:e.courseName||e.courseId.slice(0,8),generated:e.generatedCount,selected:e.finalCount,new:e.newSelected,reviews:e.reviewsSelected})))},export(){let e=JSON.stringify(runHistory,null,2);return logger.info(`[Pipeline Debug] Run history exported. Copy the returned string or use:`),logger.info(` copy(window.skuilder.pipeline.export())`),e},clear(){runHistory.length=0,logger.info(`[Pipeline Debug] Run history cleared.`)},showRegistry(){let e=getRegisteredNavigatorNames();if(e.length===0){logger.info(`[Pipeline Debug] Navigator registry is empty.`);return}console.group(`📦 Navigator Registry`),console.table(e.map(e=>{let t=getRegisteredNavigatorRole(e),n=NavigatorRoles[e];return{name:e,role:n||t||`⚠️ NONE`,source:n?`built-in`:t?`consumer`:`unclassified`,isGenerator:isGenerator(e),isFilter:isFilter(e)}})),console.groupEnd()},showStrategies(){if(this.showRegistry(),runHistory.length===0){logger.info(`[Pipeline Debug] No pipeline runs captured yet — cannot show strategy doc mapping.`);return}let e=runHistory[0];if(console.group(`🔌 Pipeline Strategy Mapping (last run)`),logger.info(`Generator: ${e.generatorName}`),e.generators&&e.generators.length>0)for(let t of e.generators)logger.info(` \u{1F4E5} ${t.name}: ${t.cardCount} cards (${t.newCount} new, ${t.reviewCount} reviews)`);if(e.filters.length>0){logger.info(`Filters:`);for(let t of e.filters)logger.info(` \u{1F538} ${t.name}: \u2191${t.boosted} \u2193${t.penalized} =${t.passed} \u2715${t.removed}`)}else logger.info(`Filters: (none)`);console.groupEnd()},async diagnoseCardSpace(e){return _activePipeline?_activePipeline.diagnoseCardSpace({threshold:e}):(logger.info(`[Pipeline Debug] No active pipeline. Run a session first.`),null)},async showTagElo(e){if(!_activePipeline){logger.info(`[Pipeline Debug] No active pipeline. Run a session first.`);return}let t=await _activePipeline.getTagEloStatus(e),n=Object.entries(t).sort(([e],[t])=>e.localeCompare(t));if(n.length===0){logger.info(`[Pipeline Debug] No tag ELO data found${e?` for pattern: ${e}`:``}.`);return}console.table(Object.fromEntries(n.map(([e,t])=>[e,{score:Math.round(t.score),count:t.count}])))},ui(){if(_uiContainer){document.body.removeChild(_uiContainer),_uiContainer=null;return}_uiContainer=document.createElement(`div`),_uiContainer.id=`sk-pipeline-debugger`,document.body.appendChild(_uiContainer),_selectedRunIndex===null&&runHistory.length>0&&(_selectedRunIndex=0),renderUI()},_selectRun(e){_selectedRunIndex=e,renderUI()},_setSearch(e){_cardSearchQuery=e,renderUI()},_copyConfig(e,t){let n=runHistory.find(t=>t.runId===e);if(!n)return;let r={runId:n.runId,timestamp:n.timestamp.toISOString(),courseId:n.courseId,courseName:n.courseName,hints:n.hints??null};copyTextToClipboard(JSON.stringify(r,null,2),t)},_copyResults(e,t){let n=runHistory.find(t=>t.runId===e);if(!n)return;let r=n.cards.filter(e=>e.selected).sort((e,t)=>t.finalScore-e.finalScore).map(e=>({cardId:e.cardId,generator:e.generator,origin:e.origin,score:Number(e.finalScore.toFixed(3)),topReason:e.provenance[0]?.reason??``})),a={runId:n.runId,label:n.hints?._label??null,finalCount:n.finalCount,newSelected:n.newSelected,reviewsSelected:n.reviewsSelected,selected:r};copyTextToClipboard(JSON.stringify(a,null,2),t)},help(){logger.info(`
|
|
203
225
|
🔧 Pipeline Debug API
|
|
204
226
|
|
|
205
227
|
Commands:
|
|
@@ -318,7 +340,7 @@ Example:
|
|
|
318
340
|
window.skuilder.mixer.showLastMix()
|
|
319
341
|
window.skuilder.mixer.explainSourceBalance()
|
|
320
342
|
window.skuilder.mixer.compareScores()
|
|
321
|
-
`)}};function mountMixerDebugger(){if(typeof window>`u`)return;let e=window;e.skuilder=e.skuilder||{},e.skuilder.mixer=mixerDebugAPI}mountMixerDebugger(),init_logger();var activeSession=null,sessionHistory=[],MAX_HISTORY=5;function startSessionTracking(e,t,n){let r=`session-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;activeSession={sessionId:r,startTime:new Date,initialQueues:{timestamp:new Date,reviewQLength:e,newQLength:t,failedQLength:n},presentations:[],queueSnapshots:[]},logger.debug(`[SessionDebugger] Started tracking session: ${r}`)}function recordCardPresentation(e,t,n,r,a,o){if(!activeSession){logger.warn(`[SessionDebugger] No active session to record presentation`);return}activeSession.presentations.push({timestamp:new Date,sequenceNumber:activeSession.presentations.length+1,cardId:e,courseId:t,courseName:n,origin:r,queueSource:a,score:o})}function snapshotQueues(e,t,n,r,a){activeSession&&activeSession.queueSnapshots.push({timestamp:new Date,reviewQLength:e,newQLength:t,failedQLength:n,reviewQNext3:r,newQNext3:a})}function endSessionTracking(){activeSession&&(activeSession.endTime=new Date,sessionHistory.unshift(activeSession),sessionHistory.length>MAX_HISTORY&&sessionHistory.pop(),logger.debug(`[SessionDebugger] Ended session: ${activeSession.sessionId}`),activeSession=null)}function showCurrentQueue(){if(!activeSession){logger.info(`[Session Debug] No active session.`);return}let e=activeSession.queueSnapshots[activeSession.queueSnapshots.length-1]||activeSession.initialQueues;console.group(`📊 Current Queue State`),logger.info(`Review Queue: ${e.reviewQLength} cards`),e.reviewQNext3&&e.reviewQNext3.length>0&&logger.info(` Next: ${e.reviewQNext3.join(`, `)}`),logger.info(`New Queue: ${e.newQLength} cards`),e.newQNext3&&e.newQNext3.length>0&&logger.info(` Next: ${e.newQNext3.join(`, `)}`),logger.info(`Failed Queue: ${e.failedQLength} cards`),console.groupEnd()}function showPresentationHistory(e=0){let t=e===0&&activeSession?activeSession:sessionHistory[e];if(!t){logger.info(`[Session Debug] No session found at index ${e}`);return}console.group(`\u{1F4DC} Session History: ${t.sessionId}`),logger.info(`Started: ${t.startTime.toLocaleTimeString()}`),t.endTime&&logger.info(`Ended: ${t.endTime.toLocaleTimeString()}`),logger.info(`Cards presented: ${t.presentations.length}`),t.presentations.length>0&&console.table(t.presentations.map(e=>({"#":e.sequenceNumber,course:e.courseName||e.courseId.slice(0,8),origin:e.origin,queue:e.queueSource,score:e.score?.toFixed(3)||`-`,time:e.timestamp.toLocaleTimeString()}))),console.groupEnd()}function showInterleaving(e=0){let t=e===0&&activeSession?activeSession:sessionHistory[e];if(!t){logger.info(`[Session Debug] No session found at index ${e}`);return}console.group(`🔀 Interleaving Analysis`);let n=new Map,r=new Map;if(t.presentations.forEach(e=>{let t=e.courseName||e.courseId;n.set(t,(n.get(t)||0)+1),r.has(t)||r.set(t,{review:0,new:0,failed:0});let a=r.get(t);a[e.origin]++}),logger.info(`Course distribution:`),console.table(Array.from(n.entries()).map(([e,n])=>{let a=r.get(e);return{course:e,total:n,reviews:a.review,new:a.new,failed:a.failed,percentage:(n/t.presentations.length*100).toFixed(1)+`%`}})),t.presentations.length>0){logger.info(`
|
|
343
|
+
`)}};function mountMixerDebugger(){if(typeof window>`u`)return;let e=window;e.skuilder=e.skuilder||{},e.skuilder.mixer=mixerDebugAPI}mountMixerDebugger(),init_logger(),init_PipelineDebugger();var activeSession=null,sessionHistory=[],MAX_HISTORY=5;function startSessionTracking(e,t,n){clearRunHistory();let r=`session-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;activeSession={sessionId:r,startTime:new Date,initialQueues:{timestamp:new Date,reviewQLength:e,newQLength:t,failedQLength:n},presentations:[],queueSnapshots:[]},logger.debug(`[SessionDebugger] Started tracking session: ${r}`)}function recordCardPresentation(e,t,n,r,a,o){if(!activeSession){logger.warn(`[SessionDebugger] No active session to record presentation`);return}activeSession.presentations.push({timestamp:new Date,sequenceNumber:activeSession.presentations.length+1,cardId:e,courseId:t,courseName:n,origin:r,queueSource:a,score:o})}function snapshotQueues(e,t,n,r,a){activeSession&&activeSession.queueSnapshots.push({timestamp:new Date,reviewQLength:e,newQLength:t,failedQLength:n,reviewQNext3:r,newQNext3:a})}function endSessionTracking(){activeSession&&(activeSession.endTime=new Date,sessionHistory.unshift(activeSession),sessionHistory.length>MAX_HISTORY&&sessionHistory.pop(),logger.debug(`[SessionDebugger] Ended session: ${activeSession.sessionId}`),activeSession=null)}function showCurrentQueue(){if(!activeSession){logger.info(`[Session Debug] No active session.`);return}let e=activeSession.queueSnapshots[activeSession.queueSnapshots.length-1]||activeSession.initialQueues;console.group(`📊 Current Queue State`),logger.info(`Review Queue: ${e.reviewQLength} cards`),e.reviewQNext3&&e.reviewQNext3.length>0&&logger.info(` Next: ${e.reviewQNext3.join(`, `)}`),logger.info(`New Queue: ${e.newQLength} cards`),e.newQNext3&&e.newQNext3.length>0&&logger.info(` Next: ${e.newQNext3.join(`, `)}`),logger.info(`Failed Queue: ${e.failedQLength} cards`),console.groupEnd()}function showPresentationHistory(e=0){let t=e===0&&activeSession?activeSession:sessionHistory[e];if(!t){logger.info(`[Session Debug] No session found at index ${e}`);return}console.group(`\u{1F4DC} Session History: ${t.sessionId}`),logger.info(`Started: ${t.startTime.toLocaleTimeString()}`),t.endTime&&logger.info(`Ended: ${t.endTime.toLocaleTimeString()}`),logger.info(`Cards presented: ${t.presentations.length}`),t.presentations.length>0&&console.table(t.presentations.map(e=>({"#":e.sequenceNumber,course:e.courseName||e.courseId.slice(0,8),origin:e.origin,queue:e.queueSource,score:e.score?.toFixed(3)||`-`,time:e.timestamp.toLocaleTimeString()}))),console.groupEnd()}function showInterleaving(e=0){let t=e===0&&activeSession?activeSession:sessionHistory[e];if(!t){logger.info(`[Session Debug] No session found at index ${e}`);return}console.group(`🔀 Interleaving Analysis`);let n=new Map,r=new Map;if(t.presentations.forEach(e=>{let t=e.courseName||e.courseId;n.set(t,(n.get(t)||0)+1),r.has(t)||r.set(t,{review:0,new:0,failed:0});let a=r.get(t);a[e.origin]++}),logger.info(`Course distribution:`),console.table(Array.from(n.entries()).map(([e,n])=>{let a=r.get(e);return{course:e,total:n,reviews:a.review,new:a.new,failed:a.failed,percentage:(n/t.presentations.length*100).toFixed(1)+`%`}})),t.presentations.length>0){logger.info(`
|
|
322
344
|
Presentation sequence (first 20):`);let e=t.presentations.slice(0,20).map((e,t)=>`${t+1}. ${e.courseName||e.courseId.slice(0,8)} (${e.origin})`).join(`
|
|
323
345
|
`);logger.info(e)}let a=0,o=1,s=t.presentations[0]?.courseId;for(let e=1;e<t.presentations.length;e++)t.presentations[e].courseId===s?(o++,a=Math.max(a,o)):(s=t.presentations[e].courseId,o=1);a>3&&(logger.info(`
|
|
324
346
|
\u26A0\uFE0F Detected clustering: max ${a} cards from same course in a row`),logger.info(`This suggests cards are sorted by score rather than round-robin by course.`)),console.groupEnd()}var sessionDebugAPI={get sessions(){return[...sessionHistory]},get active(){return activeSession},showQueue(){showCurrentQueue()},showHistory(e=0){showPresentationHistory(e)},showInterleaving(e=0){showInterleaving(e)},listSessions(){if(activeSession&&logger.info(`Active session: ${activeSession.sessionId} (${activeSession.presentations.length} cards presented)`),sessionHistory.length===0){logger.info(`[Session Debug] No completed sessions in history.`);return}console.table(sessionHistory.map((e,t)=>({index:t,id:e.sessionId.slice(-8),started:e.startTime.toLocaleTimeString(),ended:e.endTime?.toLocaleTimeString()||`incomplete`,cards:e.presentations.length})))},export(){let e={active:activeSession,history:sessionHistory},t=JSON.stringify(e,null,2);return logger.info(`[Session Debug] Session data exported. Copy the returned string or use:`),logger.info(` copy(window.skuilder.session.export())`),t},clear(){sessionHistory.length=0,logger.info(`[Session Debug] Session history cleared.`)},help(){logger.info(`
|
|
@@ -345,10 +367,10 @@ Example:
|
|
|
345
367
|
startTime: ${this.startTime}
|
|
346
368
|
endTime: ${this.endTime}
|
|
347
369
|
defaultBatchLimit: ${this._defaultBatchLimit}
|
|
348
|
-
initialReviewCap: ${this._initialReviewCap}`)}tick(){this._secondsRemaining=Math.floor((this.endTime.valueOf()-Date.now())/1e3),this._secondsRemaining<=0&&clearInterval(this._intervalHandle)}estimateCleanupTime(){let e=0;for(let t=0;t<this.failedQ.length;t++){let n=this.failedQ.peek(t),r=this._sessionRecord.find(e=>e.item.cardID===n.cardID),a=0;if(r){for(let e=0;e<r.records.length;e++)a+=r.records[e].timeSpent;a/=r.records.length,e+=a}}let t=e/1e3;return this.log(`Failed card cleanup estimate: ${Math.round(t)}`),t}estimateReviewTime(){let e=5*this.reviewQ.length;return this.log(`Review card time estimate: ${e}`),e}async prepareSession(){if(this.sources.some(e=>typeof e.getWeightedCards!=`function`))throw Error(`[SessionController] All content sources must implement getWeightedCards().`);let e=await this.getWeightedContent();this._wellIndicatedRemaining=e,e>=0&&e<_SessionController.MIN_WELL_INDICATED&&this.log(`[Init] Only ${e}/${_SessionController.MIN_WELL_INDICATED} well-indicated cards in initial load`),await this.hydrationService.ensureHydratedCards(),startSessionTracking(this.reviewQ.length,this.newQ.length,this.failedQ.length),this._intervalHandle=setInterval(()=>{this.tick()},1e3)}async requestReplan(e){let t=this.normalizeReplanOptions(e);
|
|
370
|
+
initialReviewCap: ${this._initialReviewCap}`)}tick(){this._secondsRemaining=Math.floor((this.endTime.valueOf()-Date.now())/1e3),this._secondsRemaining<=0&&clearInterval(this._intervalHandle)}estimateCleanupTime(){let e=0;for(let t=0;t<this.failedQ.length;t++){let n=this.failedQ.peek(t),r=this._sessionRecord.find(e=>e.item.cardID===n.cardID),a=0;if(r){for(let e=0;e<r.records.length;e++)a+=r.records[e].timeSpent;a/=r.records.length,e+=a}}let t=e/1e3;return this.log(`Failed card cleanup estimate: ${Math.round(t)}`),t}estimateReviewTime(){let e=5*this.reviewQ.length;return this.log(`Review card time estimate: ${e}`),e}async prepareSession(){if(this.sources.some(e=>typeof e.getWeightedCards!=`function`))throw Error(`[SessionController] All content sources must implement getWeightedCards().`);let e=await this.getWeightedContent();this._wellIndicatedRemaining=e,e>=0&&e<_SessionController.MIN_WELL_INDICATED&&this.log(`[Init] Only ${e}/${_SessionController.MIN_WELL_INDICATED} well-indicated cards in initial load`),await this.hydrationService.ensureHydratedCards(),startSessionTracking(this.reviewQ.length,this.newQ.length,this.failedQ.length),this._intervalHandle=setInterval(()=>{this.tick()},1e3)}async requestReplan(e){let t=this.normalizeReplanOptions(e);(t.hints||t.label||t.limit)&&(this._depletionReplanAttempted=!1);let n=this._replanHasIntent(t);if(this._replanPromise){if(!n)return this.log(`Replan already in progress, coalescing unhinted auto-replan`),this._replanPromise;let e=t.label?` [${t.label}]`:``;this.log(`Replan in progress; queueing hint-bearing replan${e} behind in-flight run`);let r=this._replanPromise.catch(()=>void 0).then(()=>this._runReplan(t));return this._replanPromise=r.finally(()=>{this._replanPromise===r&&(this._replanPromise=null)}),r}let r=this._runReplan(t);this._replanPromise=r.finally(()=>{this._replanPromise===r&&(this._replanPromise=null)}),await r}_replanHasIntent(e){return!!(e.label||e.limit!==void 0||e.minFollowUpCards!==void 0||e.mode&&e.mode!==`replace`||e.hints&&Object.keys(e.hints).length>0)}async _runReplan(e){e.hints||(e.hints={});let t=e.hints,n=new Set(t.excludeCards??[]);this._currentCard?.item.cardID&&n.add(this._currentCard.item.cardID);for(let e of this._sessionRecord)n.add(e.card.card_id);if(this.newQ.length>0&&n.add(this.newQ.peek(0).cardID),t.excludeCards=[...n],e.hints){let t=e.label?{...e.hints,_label:e.label}:e.hints;for(let e of this.sources)e.setEphemeralHints?.(t)}let r=e.label?` [${e.label}]`:``;this.log(`Mid-session replan requested${r} (limit: ${e.limit??`default`}, mode: ${e.mode??`replace`}${e.hints?`, with hints`:``})`),e.minFollowUpCards!==void 0&&e.minFollowUpCards>0&&(this._minCardsGuarantee=Math.max(this._minCardsGuarantee,e.minFollowUpCards),this.log(`[Replan] Card guarantee set to ${this._minCardsGuarantee}`)),await this._executeReplan(e)}normalizeReplanOptions(e){if(!e)return{};let t=[`hints`,`limit`,`mode`,`label`,`minFollowUpCards`];return Object.keys(e).some(e=>t.includes(e))?e:{hints:e}}async _executeReplan(e={}){let t=e.limit,n=e.mode??`replace`,r=await this.getWeightedContent({replan:!0,additive:n===`merge`,limit:t});this._wellIndicatedRemaining=r,t!==void 0&&t<this._defaultBatchLimit?(this._suppressQualityReplan=!0,this.log(`[Replan] Burst mode (limit=${t}): suppressing quality-based auto-replan`)):this._suppressQualityReplan=!1,r>=0&&r<_SessionController.MIN_WELL_INDICATED&&this.log(`[Replan] Only ${r}/${_SessionController.MIN_WELL_INDICATED} well-indicated cards after replan`),this.newQ.length>0&&(this._depletionReplanAttempted=!1),await this.hydrationService.ensureHydratedCards();let a=e.label?` [${e.label}]`:``;this.log(`Replan complete${a}: newQ now has ${this.newQ.length} cards (mode=${n})`),snapshotQueues(this.reviewQ.length,this.newQ.length,this.failedQ.length)}addTime(e){this.endTime=new Date(this.endTime.valueOf()+1e3*e)}get failedCount(){return this.failedQ.length}toString(){return`Session: ${this.reviewQ.length} Reviews, ${this.newQ.length} New, ${this.failedQ.length} failed`}reportString(){return`${this.reviewQ.dequeueCount} Reviews, ${this.newQ.dequeueCount} New, ${this.failedQ.dequeueCount} failed`}getDebugInfo(){let e=this.sources.some(e=>typeof e.getWeightedCards==`function`),extractQueueItems=(e,t=10)=>{let n=[];for(let r=0;r<Math.min(e.length,t);r++){let t=e.peek(r);n.push({courseID:t.courseID||`unknown`,cardID:t.cardID||`unknown`,status:t.status||`unknown`})}return n};return{api:{mode:e?`weighted`:`legacy`,description:e?`Using getWeightedCards() API with scored candidates`:`ERROR: getWeightedCards() not a function.`},reviewQueue:{length:this.reviewQ.length,dequeueCount:this.reviewQ.dequeueCount,items:extractQueueItems(this.reviewQ)},newQueue:{length:this.newQ.length,dequeueCount:this.newQ.dequeueCount,items:extractQueueItems(this.newQ)},failedQueue:{length:this.failedQ.length,dequeueCount:this.failedQ.dequeueCount,items:extractQueueItems(this.failedQ)},hydratedCache:{count:this.hydrationService.hydratedCount,cardIds:this.hydrationService.getHydratedCardIds()},replan:{inProgress:this._replanPromise!==null,suppressQualityReplan:this._suppressQualityReplan,defaultBatchLimit:this._defaultBatchLimit,minCardsGuarantee:this._minCardsGuarantee}}}async getWeightedContent(e){let t=e?.replan??!1,n=e?.additive??!1,r=e?.limit??this._defaultBatchLimit,a=t?r:r+this._initialReviewCap,o=[];for(let e=0;e<this.sources.length;e++){let t=this.sources[e];try{let n=(await t.getWeightedCards(a)).cards;o.push({sourceIndex:e,weighted:n})}catch(t){if(this.error(`Failed to get content from source ${e}:`,t),this.sources.length===1)throw Error(`Cannot start session: failed to load content from source ${e}`)}}if(o.length===0){if(t)return this.log(`Replan: no content from any source, keeping existing newQ`),-1;throw Error(`Cannot start session: failed to load content from all ${this.sources.length} source(s). Check logs for details.`)}let s=this.mixer.mix(o,a*this.sources.length),c=o.map(e=>e.weighted[0]?.courseId||`source-${e.sourceIndex}`);await Promise.all(c.map(async e=>{if(!this.courseNameCache.has(e))try{let t=await this.dataLayer.getCoursesDB().getCourseConfig(e);this.courseNameCache.set(e,t.name)}catch{}}));let l=c.map(e=>this.courseNameCache.get(e)),u=this.mixer instanceof QuotaRoundRobinMixer?Math.ceil(a*this.sources.length/o.length):void 0;captureMixerRun(this.mixer.constructor.name,o,c,l,a*this.sources.length,u,s);let d=s.filter(e=>getCardOrigin(e)===`review`).slice(0,this._initialReviewCap),p=s.filter(e=>getCardOrigin(e)===`new`).slice(0,r);logger.debug(`[reviews] got ${d.length} reviews from mixer`);let m=t?`Replan content:
|
|
349
371
|
`:`Mixed content session created with:
|
|
350
372
|
`;if(!t)for(let e of d){let t={cardID:e.cardId,courseID:e.courseId,contentSourceType:`course`,contentSourceID:e.courseId,reviewID:e.reviewID,status:`review`};this.reviewQ.add(t,t.cardID),m+=`Review: ${e.courseId}::${e.cardId} (score: ${e.score.toFixed(2)})
|
|
351
373
|
`}let g=p.filter(e=>e.score>=_SessionController.WELL_INDICATED_SCORE).length,_=[];for(let e of p){let t={cardID:e.cardId,courseID:e.courseId,contentSourceType:`course`,contentSourceID:e.courseId,status:`new`};_.push(t),m+=`New: ${e.courseId}::${e.cardId} (score: ${e.score.toFixed(2)})
|
|
352
374
|
`}if(n){let e=this.newQ.mergeToFront(_,e=>e.cardID);m+=`Additive merge: ${e} new cards added to front of newQ
|
|
353
375
|
`}else if(t)this.newQ.replaceAll(_,e=>e.cardID);else for(let e of _)this.newQ.add(e,e.cardID);return this.log(m),g}_getItemsToHydrate(){let e=[],t=2;for(let t=0;t<Math.min(2,this.reviewQ.length);t++)e.push(this.reviewQ.peek(t));for(let t=0;t<Math.min(2,this.newQ.length);t++)e.push(this.newQ.peek(t));for(let t=0;t<Math.min(2,this.failedQ.length);t++)e.push(this.failedQ.peek(t));return e}_selectNextItemToHydrate(){let e=Math.random(),t=.1,n=.75;if(this.reviewQ.length===0&&this.failedQ.length===0&&this.newQ.length===0||this._secondsRemaining<2&&this.failedQ.length===0&&this._minCardsGuarantee<=0)return null;if(this._secondsRemaining<=0&&this._minCardsGuarantee<=0)return this.failedQ.length>0?this.failedQ.peek(0):null;if(this.newQ.dequeueCount<this.sources.length&&this.newQ.length)return this.newQ.peek(0);let r=this.estimateCleanupTime(),a=this.estimateReviewTime();return this._secondsRemaining-(r+a)>20?(t=.5,n=.9):this._secondsRemaining-r>20?(t=.05,n=.9):(t=.01,n=.1),this.failedQ.length===0&&(n=1),this.reviewQ.length===0&&(t=n),e<t&&this.newQ.length?this.newQ.peek(0):e<n&&this.reviewQ.length?this.reviewQ.peek(0):this.failedQ.length?this.failedQ.peek(0):(this.log(`No more cards available for the session!`),null)}async nextCard(e=`dismiss-success`){if(this.dismissCurrentCard(e),this._minCardsGuarantee>0&&(this._minCardsGuarantee--,this.log(`[CardGuarantee] ${this._minCardsGuarantee} guaranteed cards remaining`)),this._replanPromise&&(this.log(`nextCard: awaiting in-flight replan before drawing`),await this._replanPromise),this.newQ.length<=1&&this._secondsRemaining>0&&!this._replanPromise&&!this._depletionReplanAttempted){this._suppressQualityReplan=!1,this._depletionReplanAttempted=!0;let e=this.reviewQ.length+this.failedQ.length;this.newQ.length===0&&e===0?(this.log(`[AutoReplan:depletion] All queues empty with ${this._secondsRemaining}s remaining. Awaiting replan.`),await this.requestReplan()):(this.log(`[AutoReplan:depletion] newQ has ${this.newQ.length} card(s) (${e} in other queues) with ${this._secondsRemaining}s remaining. Triggering background replan.`),this.requestReplan())}if(!this._suppressQualityReplan&&this._wellIndicatedRemaining<=3&&this.newQ.length>0&&!this._replanPromise&&(this.log(`[AutoReplan:quality] ${this._wellIndicatedRemaining} well-indicated cards remaining (newQ: ${this.newQ.length}). Triggering background replan.`),this.requestReplan()),this._secondsRemaining<=0&&this.failedQ.length===0&&this._minCardsGuarantee<=0)return this._currentCard=null,endSessionTracking(),null;let t=20;for(let e=0;e<20;e++){let e=this._selectNextItemToHydrate();if(!e)return this._currentCard=null,endSessionTracking(),null;let t=this.hydrationService.getHydratedCard(e.cardID);if(t||(t=await this.hydrationService.waitForCard(e.cardID)),this.removeItemFromQueue(e),t){await this.hydrationService.ensureHydratedCards(),this._currentCard=t;let n=e.status===`review`||e.status===`failed-review`?`review`:e.status===`new`||e.status===`failed-new`?`new`:`failed`,r=e.status.startsWith(`failed`)?`failedQ`:e.status===`review`?`reviewQ`:`newQ`;return recordCardPresentation(e.cardID,e.courseID,this.courseNameCache.get(e.courseID),n,r),snapshotQueues(this.reviewQ.length,this.newQ.length,this.failedQ.length),t}this.log(`Skipping card ${e.cardID}: hydration failed, trying next`),isReview(e)&&this.srsService.removeReview(e.reviewID)}return this.log(`Exhausted 20 skip attempts finding a hydratable card`),this._currentCard=null,endSessionTracking(),null}async submitResponse(e,t,n,r,a,o,s,c,l){let u={...r.item};return await this.services.response.processResponse(e,t,u,n,r,a,o,s,c,l)}dismissCurrentCard(e=`dismiss-success`){if(this._currentCard)if(e===`dismiss-success`)this.hydrationService.removeCard(this._currentCard.item.cardID);else if(e===`marked-failed`){let e;e=isReview(this._currentCard.item)?{cardID:this._currentCard.item.cardID,courseID:this._currentCard.item.courseID,contentSourceID:this._currentCard.item.contentSourceID,contentSourceType:this._currentCard.item.contentSourceType,status:`failed-review`,reviewID:this._currentCard.item.reviewID}:{cardID:this._currentCard.item.cardID,courseID:this._currentCard.item.courseID,contentSourceID:this._currentCard.item.contentSourceID,contentSourceType:this._currentCard.item.contentSourceType,status:`failed-new`},this.failedQ.add(e,e.cardID)}else (e===`dismiss-error`||e===`dismiss-failed`)&&this.hydrationService.removeCard(this._currentCard.item.cardID)}removeItemFromQueue(e){this.reviewQ.peek(0)?.cardID===e.cardID?this.reviewQ.dequeue(e=>e.cardID):this.newQ.peek(0)?.cardID===e.cardID?(this.newQ.dequeue(e=>e.cardID),this._wellIndicatedRemaining>0&&this._wellIndicatedRemaining--):this.failedQ.peek(0)?.cardID===e.cardID&&this.failedQ.dequeue(e=>e.cardID)}async endSession(){if(!this._sessionRecord||this._sessionRecord.length===0)return;let e=this._sessionRecord.flatMap(e=>e.records).filter(e=>e.userAnswer!==void 0);if(e.length===0)return;let t=null,n=[];for(let e of this.sources)if(e.getOrchestrationContext){try{t=await e.getOrchestrationContext(),e.getStrategyIds&&n.push(...e.getStrategyIds())}catch(e){logger.warn(`[SessionController] Failed to get orchestration context: ${e}`)}if(t)break}if(!t){logger.debug(`[SessionController] No orchestration context available, skipping outcome recording`);return}let r=new Date().toISOString(),a=new Date(this.startTime).toISOString();await recordUserOutcome(t,a,r,e,n)}},_defineProperty(_SessionController2,`MIN_WELL_INDICATED`,5),_defineProperty(_SessionController2,`WELL_INDICATED_SCORE`,.1),_SessionController2);init_TagFilteredContentSource(),init_factory();export{processCustomQuestionsData as $,getDbPath as A,isFilter as B,createOrchestrationContext as C,getCardHistoryID as D,getAppDataDirectory as E,hasRegisteredNavigator as F,log as G,isQuestionRecord as H,importParsedCards as I,mountPipelineDebugger as J,mixerDebugAPI as K,initializeDataDirectory as L,getRegisteredNavigatorNames as M,getRegisteredNavigatorRole as N,getCardOrigin as O,getStudySource as P,pipelineDebugAPI as Q,initializeDataLayer as R,computeSpread as S,ensureAppDataDirectory as T,isQuestionTypeRegistered as U,isGenerator as V,isReview as W,mountUserDBDebugger as X,mountSessionDebugger as Y,newInterval as Z,buildStrategyStateId as _,validateStaticCourse as _t,ENV as a,registerSeedData as at,computeEffectiveWeight as b,Loggable as c,scoreAccuracyInZone as ct,NavigatorRoles as d,startSessionTracking as dt,recordCardPresentation as et,Navigators as f,updateLearningState as ft,areQuestionRecords as g,validateProcessorConfig as gt,TagFilteredContentSource as h,validateMigration as ht,DocTypePrefixes as i,registerQuestionType as it,getRegisteredNavigator as j,getDataLayer as k,NOT_SET as l,sessionDebugAPI as lt,SessionController as m,userDBDebugAPI as mt,CourseLookup as n,registerDataShape as nt,FileSystemError as o,removeDataShape as ot,QuotaRoundRobinMixer as p,updateStrategyWeight as pt,mountMixerDebugger as q,DocType as r,registerNavigator as rt,GuestUsername as s,removeQuestionType as st,ContentNavigator as t,recordUserOutcome as tt,NavigatorRole as u,snapshotQueues as ut,captureMixerRun as v,endSessionTracking as w,computeOutcomeSignal as x,computeDeviation as y,initializeNavigatorRegistry as z};
|
|
354
|
-
//# sourceMappingURL=dist-
|
|
376
|
+
//# sourceMappingURL=dist-DA7EuQY2.js.map
|