vibelearn 0.1.3 → 0.1.4
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibelearn",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Learn from every coding session — automatically extracts concepts from your Claude Code sessions, generates adaptive quiz questions across 7 formats, and tracks mastery with spaced repetition.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Ahun Atajanov"
|
package/plugin/package.json
CHANGED
|
@@ -114,7 +114,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
114
114
|
${c}`}var xP=new Set([".js",".jsx",".ts",".tsx",".mjs",".cjs",".py",".pyw",".go",".rs",".rb",".java",".cs",".cpp",".c",".h",".hpp",".swift",".kt",".php",".vue",".svelte"]),kP=new Set(["node_modules",".git","dist","build",".next","__pycache__",".venv","venv","env",".env","target","vendor",".cache",".turbo","coverage",".nyc_output",".claude",".smart-file-read"]),SP=512*1024;async function*u$(t,e,r=20){if(r<=0)return;let n;try{n=await(0,zn.readdir)(t,{withFileTypes:!0})}catch{return}for(let o of n){if(o.name.startsWith(".")&&o.name!=="."||kP.has(o.name))continue;let i=(0,hi.join)(t,o.name);if(o.isDirectory())yield*u$(i,e,r-1);else if(o.isFile()){let a=o.name.slice(o.name.lastIndexOf("."));xP.has(a)&&(yield i)}}}async function wP(t){try{let e=await(0,zn.stat)(t);if(e.size>SP||e.size===0)return null;let r=await(0,zn.readFile)(t,"utf-8");return r.slice(0,1e3).includes("\0")?null:r}catch{return null}}async function l$(t,e,r={}){let n=r.maxResults||20,o=e.toLowerCase(),i=o.split(/[\s_\-./]+/).filter(h=>h.length>0),a=[];for await(let h of u$(t,t)){if(r.filePattern&&!(0,hi.relative)(t,h).toLowerCase().includes(r.filePattern.toLowerCase()))continue;let _=await wP(h);_&&a.push({absolutePath:h,relativePath:(0,hi.relative)(t,h),content:_})}let s=a$(a),c=[],u=[],l=0;for(let[h,_]of s){l+=zP(_);let E=Ns(h.toLowerCase(),i)>0,I=[],A=(j,Le)=>{for(let de of j){let Bt=0,Qe="",Wt=Ns(de.name.toLowerCase(),i);Wt>0&&(Bt+=Wt*3,Qe="name match"),de.signature.toLowerCase().includes(o)&&(Bt+=2,Qe=Qe?`${Qe} + signature`:"signature match"),de.jsdoc&&de.jsdoc.toLowerCase().includes(o)&&(Bt+=1,Qe=Qe?`${Qe} + jsdoc`:"jsdoc match"),Bt>0&&(E=!0,I.push({filePath:h,symbolName:Le?`${Le}.${de.name}`:de.name,kind:de.kind,signature:de.signature,jsdoc:de.jsdoc,lineStart:de.lineStart,lineEnd:de.lineEnd,matchReason:Qe})),de.children&&A(de.children,de.name)}};A(_.symbols),E&&(c.push(_),u.push(...I))}u.sort((h,_)=>{let b=Ns(h.symbolName.toLowerCase(),i);return Ns(_.symbolName.toLowerCase(),i)-b});let d=u.slice(0,n),p=new Set(d.map(h=>h.filePath)),f=c.filter(h=>p.has(h.filePath)).slice(0,n),g=f.reduce((h,_)=>h+_.foldedTokenEstimate,0);return{foldedFiles:f,matchingSymbols:d,totalFilesScanned:a.length,totalSymbolsFound:l,tokenEstimate:g}}function Ns(t,e){let r=0;for(let n of e)if(t===n)r+=10;else if(t.includes(n))r+=5;else{let o=0,i=0;for(let a of n){let s=t.indexOf(a,o);s!==-1&&(i++,o=s+1)}i===n.length&&(r+=1)}return r}function zP(t){let e=t.symbols.length;for(let r of t.symbols)r.children&&(e+=r.children.length);return e}function d$(t,e){let r=[];if(r.push(`\u{1F50D} Smart Search: "${e}"`),r.push(` Scanned ${t.totalFilesScanned} files, found ${t.totalSymbolsFound} symbols`),r.push(` ${t.matchingSymbols.length} matches across ${t.foldedFiles.length} files (~${t.tokenEstimate} tokens for folded view)`),r.push(""),t.matchingSymbols.length===0)return r.push(" No matching symbols found."),r.join(`
|
|
115
115
|
`);r.push("\u2500\u2500 Matching Symbols \u2500\u2500"),r.push("");for(let n of t.matchingSymbols){if(r.push(` ${n.kind} ${n.symbolName} (${n.filePath}:${n.lineStart+1})`),r.push(` ${n.signature}`),n.jsdoc){let o=n.jsdoc.split(`
|
|
116
116
|
`).find(i=>i.replace(/^[\s*/]+/,"").trim().length>0);o&&r.push(` \u{1F4AC} ${o.replace(/^[\s*/]+/,"").trim()}`)}r.push("")}r.push("\u2500\u2500 Folded File Views \u2500\u2500"),r.push("");for(let n of t.foldedFiles)r.push(wn(n)),r.push("");return r.push("\u2500\u2500 Actions \u2500\u2500"),r.push(" To see full implementation: use smart_unfold with file path and symbol name"),r.join(`
|
|
117
|
-
`)}var jf=require("node:fs/promises"),Rs=require("node:path"),IP="0.1.
|
|
117
|
+
`)}var jf=require("node:fs/promises"),Rs=require("node:path"),IP="0.1.4";console.log=(...t)=>{ve.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var p$={search:"/api/search",timeline:"/api/timeline"};async function f$(t,e){ve.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});try{let r=new URLSearchParams;for(let[a,s]of Object.entries(e))s!=null&&r.append(a,String(s));let n=`${t}?${r}`,o=await Os(n);if(!o.ok){let a=await o.text();throw new Error(`Worker API error (${o.status}): ${a}`)}let i=await o.json();return ve.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),i}catch(r){return ve.error("SYSTEM","\u2190 Worker API error",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function EP(t,e){ve.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{let r=await Os(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!r.ok){let o=await r.text();throw new Error(`Worker API error (${r.status}): ${o}`)}let n=await r.json();return ve.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}catch(r){return ve.error("HTTP","Worker API error (POST)",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function TP(){try{return(await Os("/api/health")).ok}catch(t){return ve.debug("SYSTEM","Worker health check failed",{},t),!1}}var m$=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW):
|
|
118
118
|
1. search(query) \u2192 Get index with IDs (~50-100 tokens/result)
|
|
119
119
|
2. timeline(anchor=ID) \u2192 Get context around interesting results
|
|
120
120
|
3. get_observations([IDs]) \u2192 Fetch full details ONLY for filtered IDs
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
"use strict";var B=Object.create;var
|
|
2
|
+
"use strict";var B=Object.create;var O=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var J=Object.getPrototypeOf,X=Object.prototype.hasOwnProperty;var Z=(e,n,t,s)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of K(n))!X.call(e,r)&&r!==t&&O(e,r,{get:()=>n[r],enumerable:!(s=G(n,r))||s.enumerable});return e};var ee=(e,n,t)=>(t=e!=null?B(J(e)):{},Z(n||!e||!e.__esModule?O(t,"default",{value:e,enumerable:!0}):t,e));var j=require("readline"),N=require("bun:sqlite"),q=require("path"),T=require("os"),m=require("fs");function h(e,n){let t=e+n;return t===0?0:e/t}function x(e){return e>=.85?"senior":e>=.5?"mid":"junior"}function M(e,n){let t=Math.floor(Date.now()/1e3),s=e.query("SELECT * FROM vl_developer_profile WHERE concept_name = ?").get(n.conceptName);if(!s){let _=n.isCorrect?1:0,a=n.isCorrect?0:1,v=h(_,a),f=n.isCorrect?1:0,S=x(v);return e.run(`INSERT INTO vl_developer_profile
|
|
3
3
|
(concept_name, category, first_seen_at, last_seen_at, encounter_count,
|
|
4
4
|
correct_answers, incorrect_answers, current_level, streak_count, mastery_score)
|
|
5
|
-
VALUES (?, ?, ?, ?, 1, ?, ?, ?, ?, ?)`,[n.conceptName,n.category,t,t,
|
|
5
|
+
VALUES (?, ?, ?, ?, 1, ?, ?, ?, ?, ?)`,[n.conceptName,n.category,t,t,_,a,S,f,v]),{concept_name:n.conceptName,category:n.category,first_seen_at:t,last_seen_at:t,encounter_count:1,correct_answers:_,incorrect_answers:a,current_level:S,streak_count:f,mastery_score:v}}let r=s.correct_answers+(n.isCorrect?1:0),i=s.incorrect_answers+(n.isCorrect?0:1),c=h(r,i),l=n.isCorrect?s.streak_count+1:0,u=x(c);return e.run(`UPDATE vl_developer_profile SET
|
|
6
6
|
last_seen_at = ?,
|
|
7
7
|
encounter_count = encounter_count + 1,
|
|
8
8
|
correct_answers = ?,
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
questions_answered = questions_answered + 1,
|
|
15
15
|
correct_answers = correct_answers + ?
|
|
16
16
|
WHERE date = ?`,[n?1:0,t]):e.run(`INSERT INTO vl_daily_streaks (date, questions_answered, correct_answers, streak_continues)
|
|
17
|
-
VALUES (?, 1, ?, 1)`,[t,n?1:0])}function
|
|
17
|
+
VALUES (?, 1, ?, 1)`,[t,n?1:0])}function F(e){let{isCorrect:n,currentEaseFactor:t,currentIntervalDays:s,currentRepetitions:r,nowEpoch:i}=e;if(!n){let _=Math.max(1.3,t-.2);return{nextReviewAt:i+86400,easeFactor:_,intervalDays:1,repetitions:0}}let c=t+.1,l=r+1,u;return l===1?u=1:l===2?u=6:u=Math.round(s*t),{nextReviewAt:i+u*86400,easeFactor:c,intervalDays:u,repetitions:l}}function $(e,n,t){e.run(`UPDATE vl_questions
|
|
18
18
|
SET next_review_at = ?,
|
|
19
19
|
ease_factor = ?,
|
|
20
20
|
interval_days = ?,
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
${r}
|
|
31
31
|
ORDER BY q.next_review_at ASC NULLS FIRST, q.created_at DESC
|
|
32
32
|
LIMIT ?
|
|
33
|
-
`).all(...i)}var R=["junior","mid","senior"],ne=3;function te(e){let n=R.indexOf(e);return n===-1||n>=R.length-1?"senior":R[n+1]}function oe(e){let n=R.indexOf(e);return n<=0?"junior":R[n-1]}function P(e,n){let t=e.query("SELECT current_level FROM vl_developer_profile WHERE concept_name = ?").get(n.conceptName),s=!t,r=t?.current_level??"junior",i=M(e,n),c=i.current_level,l=!1,u=!1;if(!s)if(n.isCorrect&&i.streak_count>=ne){let a=te(r);a!==r?(c=a,l=!0,e.run("UPDATE vl_developer_profile SET current_level = ?, streak_count = 0 WHERE concept_name = ?",[c,n.conceptName]),i.streak_count=0):(c=r,e.run("UPDATE vl_developer_profile SET current_level = ? WHERE concept_name = ?",[c,n.conceptName]))}else if(n.isCorrect)c=r,e.run("UPDATE vl_developer_profile SET current_level = ? WHERE concept_name = ?",[c,n.conceptName]);else{let a=oe(r);a!==r?(c=a,u=!0,e.run("UPDATE vl_developer_profile SET current_level = ? WHERE concept_name = ?",[c,n.conceptName])):(c=r,e.run("UPDATE vl_developer_profile SET current_level = ? WHERE concept_name = ?",[c,n.conceptName]))}return{profile:{...i,current_level:c},levelChanged:!s&&c!==r,previousLevel:r,promoted:l,demoted:u}}function Q(e,n,t,s){if(!e.follow_up_mid||!e.follow_up_mid.trim()||e.difficulty!=="junior"||!n||t!=="junior")return!1;let r=`followup_${e.id}`;return!s.has(r)}function z(e){return{id:`followup_${e.id}`,concept_name:e.concept_name,question_type:"open_ended",difficulty:"mid",snippet:e.snippet??null,question:e.follow_up_mid??"",options_json:null,correct:null,explanation:"(Follow-up \u2014 no single correct answer. Reflect on your understanding.)",follow_up_mid:null,is_follow_up:!0}}var b=process.env.VIBELEARN_DATA_DIR?process.env.VIBELEARN_DATA_DIR.replace("~",(0,T.homedir)()):(0,q.join)((0,T.homedir)(),".vibelearn"),
|
|
33
|
+
`).all(...i)}var R=["junior","mid","senior"],ne=3;function te(e){let n=R.indexOf(e);return n===-1||n>=R.length-1?"senior":R[n+1]}function oe(e){let n=R.indexOf(e);return n<=0?"junior":R[n-1]}function P(e,n){let t=e.query("SELECT current_level FROM vl_developer_profile WHERE concept_name = ?").get(n.conceptName),s=!t,r=t?.current_level??"junior",i=M(e,n),c=i.current_level,l=!1,u=!1;if(!s)if(n.isCorrect&&i.streak_count>=ne){let a=te(r);a!==r?(c=a,l=!0,e.run("UPDATE vl_developer_profile SET current_level = ?, streak_count = 0 WHERE concept_name = ?",[c,n.conceptName]),i.streak_count=0):(c=r,e.run("UPDATE vl_developer_profile SET current_level = ? WHERE concept_name = ?",[c,n.conceptName]))}else if(n.isCorrect)c=r,e.run("UPDATE vl_developer_profile SET current_level = ? WHERE concept_name = ?",[c,n.conceptName]);else{let a=oe(r);a!==r?(c=a,u=!0,e.run("UPDATE vl_developer_profile SET current_level = ? WHERE concept_name = ?",[c,n.conceptName])):(c=r,e.run("UPDATE vl_developer_profile SET current_level = ? WHERE concept_name = ?",[c,n.conceptName]))}return{profile:{...i,current_level:c},levelChanged:!s&&c!==r,previousLevel:r,promoted:l,demoted:u}}function Q(e,n,t,s){if(!e.follow_up_mid||!e.follow_up_mid.trim()||e.difficulty!=="junior"||!n||t!=="junior")return!1;let r=`followup_${e.id}`;return!s.has(r)}function z(e){return{id:`followup_${e.id}`,concept_name:e.concept_name,question_type:"open_ended",difficulty:"mid",snippet:e.snippet??null,question:e.follow_up_mid??"",options_json:null,correct:null,explanation:"(Follow-up \u2014 no single correct answer. Reflect on your understanding.)",follow_up_mid:null,is_follow_up:!0}}var re="0.1.4",b=process.env.VIBELEARN_DATA_DIR?process.env.VIBELEARN_DATA_DIR.replace("~",(0,T.homedir)()):(0,q.join)((0,T.homedir)(),".vibelearn"),A=(0,q.join)(b,"vibelearn.db"),L=(0,q.join)(b,"config.json");function H(){try{if((0,m.existsSync)(L))return JSON.parse((0,m.readFileSync)(L,"utf-8"))}catch{}return{}}function se(e){(0,m.existsSync)(b)||(0,m.mkdirSync)(b,{recursive:!0}),(0,m.writeFileSync)(L,JSON.stringify(e,null,2),"utf-8")}function I(){return(0,m.existsSync)(A)?new N.Database(A,{readonly:!0}):(console.log("No VibeLearn database found. Start a coding session first!"),null)}async function ie(){let e=I();if(!e)return;let n=e.query("SELECT COUNT(*) as count FROM vibelearn_session_summaries").get()?.count??0,t=e.query("SELECT COUNT(*) as count FROM vl_concepts").get()?.count??0,s=e.query("SELECT COUNT(*) as count FROM vl_questions").get()?.count??0,r=e.query(`
|
|
34
34
|
SELECT COUNT(*) as count FROM vl_questions
|
|
35
35
|
WHERE id NOT IN (SELECT DISTINCT question_id FROM vl_quiz_attempts)
|
|
36
36
|
`).get()?.count??0,i=e.query(`
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
`).get()?.count??0;console.log(`
|
|
45
45
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`),console.log(" VibeLearn Status"),console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),console.log(` Sessions analyzed : ${n}`),console.log(` Concepts captured : ${t}`),console.log(` Quiz questions : ${s} (${r} pending)`),console.log(` Mastered concepts : ${c}`),i.length>0&&(console.log(`
|
|
46
46
|
Top categories:`),i.forEach(l=>{console.log(` ${l.category.padEnd(20)} ${l.count}`)})),console.log(`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
47
|
-
`),e.close()}async function
|
|
47
|
+
`),e.close()}async function ce(){let e=I();if(!e)return;let n=e.query(`
|
|
48
48
|
SELECT concept_name, category, mastery_score, encounter_count as times_seen
|
|
49
49
|
FROM vl_developer_profile
|
|
50
50
|
WHERE mastery_score < 0.5
|
|
@@ -54,44 +54,44 @@
|
|
|
54
54
|
No knowledge gaps found. Keep coding and learning!
|
|
55
55
|
`),e.close();return}console.log(`
|
|
56
56
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`),console.log(" Knowledge Gaps (mastery < 50%)"),console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),n.forEach(t=>{let s="\u2588".repeat(Math.round(t.mastery_score*10))+"\u2591".repeat(10-Math.round(t.mastery_score*10)),r=Math.round(t.mastery_score*100);console.log(` ${t.concept_name.padEnd(30)} [${s}] ${String(r).padStart(3)}% (${t.category})`)}),console.log(`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
57
|
-
`),e.close()}async function
|
|
57
|
+
`),e.close()}async function le(e){let n=I();if(!n)return;let t=Math.floor(Date.now()/1e3),s;if(e){let o=n.query(`
|
|
58
58
|
SELECT session_id FROM vibelearn_session_summaries
|
|
59
59
|
ORDER BY generated_at DESC LIMIT 1
|
|
60
60
|
`).get();if(!o){console.log(`
|
|
61
61
|
No sessions found. Run a coding session first!
|
|
62
62
|
`),n.close();return}s=o.session_id}let r=U(n,t,s,20);if(n.close(),r.length===0){console.log(`
|
|
63
63
|
No pending questions! Great job staying on top of your learning.
|
|
64
|
-
`);return}let i=new N.Database(
|
|
64
|
+
`);return}let i=new N.Database(A),c=(0,j.createInterface)({input:process.stdin,output:process.stdout}),l=o=>new Promise(C=>c.question(o,C)),u=0,_=0,a=[...r],v=new Set(a.map(o=>o.id));console.log(`
|
|
65
65
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`),console.log(` VibeLearn Quiz \u2014 ${a.length} questions`),console.log(`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
66
66
|
`);let f=0;for(;f<a.length;){let o=a[f],C=`Q${f+1}/${a.length}`,W=o.concept_name?` [${o.concept_name}]`:"";console.log(`
|
|
67
67
|
${C} (${o.difficulty})${W}`),o.snippet&&o.snippet.trim()&&(console.log(`
|
|
68
68
|
Code:
|
|
69
69
|
`),o.snippet.split(`
|
|
70
70
|
`).forEach(y=>console.log(` ${y}`)),console.log("")),console.log(` ${o.question}
|
|
71
|
-
`);let g="",
|
|
71
|
+
`);let g="",V=Date.now();if(o.question_type==="multiple_choice"&&o.options_json)try{JSON.parse(o.options_json).forEach((E,p)=>{let w=String.fromCharCode(65+p);console.log(` ${w}) ${E}`)}),console.log(""),g=(await l(" Your answer (A/B/C/D): ")).trim().toUpperCase()}catch{g=(await l(" Your answer: ")).trim()}else if(o.question_type==="fill_in_blank")g=(await l(" Fill in: ")).trim();else if(o.question_type==="ordering"&&o.options_json)try{JSON.parse(o.options_json).forEach((E,p)=>console.log(` ${p+1}. ${E}`)),console.log(""),g=(await l(" Enter correct order (e.g. 2,4,1,3): ")).trim()}catch{g=(await l(" Your answer: ")).trim()}else o.question_type==="true_false"?g=(await l(" True or False? ")).trim().toLowerCase():(o.question_type==="open_ended"&&console.log(" (Open-ended \u2014 describe your reasoning, then press Enter)"),g=(await l(" Your answer: ")).trim());let Y=Date.now()-V,D=o.question_type==="open_ended",d=!1;!D&&o.correct!==null&&(d=g.toLowerCase()===o.correct.toLowerCase()),D?console.log(`
|
|
72
72
|
\u270E Open-ended noted.
|
|
73
73
|
`):d?(console.log(`
|
|
74
74
|
\u2713 Correct!
|
|
75
75
|
`),u++):console.log(`
|
|
76
76
|
\u2717 Incorrect. Correct answer: ${o.correct??"(see explanation)"}
|
|
77
77
|
`),console.log(` Explanation: ${o.explanation}
|
|
78
|
-
`),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
78
|
+
`),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),_++;try{let{randomUUID:y}=await import("crypto");if(i.run(`
|
|
79
79
|
INSERT INTO vl_quiz_attempts (id, question_id, answer_given, is_correct, time_taken_ms, created_at)
|
|
80
80
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
81
|
-
`,[y(),o.id,g,d?1:0,
|
|
82
|
-
`):
|
|
83
|
-
`),Q(o,d,
|
|
84
|
-
`)}}k(i,d)}catch{}f++}c.close(),i.close();let S=
|
|
85
|
-
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`),console.log(` Quiz complete: ${u}/${
|
|
86
|
-
`)}async function
|
|
81
|
+
`,[y(),o.id,g,d?1:0,Y,Math.floor(Date.now()/1e3)]),!o.is_follow_up){let E=F({isCorrect:d,currentEaseFactor:o.ease_factor??2.5,currentIntervalDays:o.interval_days??0,currentRepetitions:o.repetitions??0,nowEpoch:Math.floor(Date.now()/1e3)});$(i,o.id,E)}if(o.concept_name&&!D){let E=i.query("SELECT category FROM vl_concepts WHERE concept_name = ? LIMIT 1").get(o.concept_name),p=P(i,{conceptName:o.concept_name,category:E?.category??"general",isCorrect:d});if(p.promoted?console.log(` \u{1F389} Level up! ${o.concept_name}: ${p.previousLevel} \u2192 ${p.profile.current_level}
|
|
82
|
+
`):p.demoted&&console.log(` \u{1F4C9} Level dropped: ${o.concept_name}: ${p.previousLevel} \u2192 ${p.profile.current_level}
|
|
83
|
+
`),Q(o,d,p.profile.current_level,v)){let w=z(o);a.splice(f+1,0,w),v.add(w.id),console.log(` \u2795 Follow-up added: ${w.question.slice(0,60)}...
|
|
84
|
+
`)}}k(i,d)}catch{}f++}c.close(),i.close();let S=_>0?Math.round(u/_*100):0;console.log(`
|
|
85
|
+
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`),console.log(` Quiz complete: ${u}/${_} correct (${S}%)`),console.log(`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
86
|
+
`)}async function ae(e,n){if(n){let s=H();if(s.api_key){let r=s.api_key.slice(0,6)+"..."+s.api_key.slice(-4);console.log(`
|
|
87
87
|
Logged in: API key ${r}
|
|
88
88
|
`)}else console.log(`
|
|
89
89
|
Not logged in. Run: vl login <api-key>
|
|
90
90
|
`);return}e||(console.error(`
|
|
91
91
|
Usage: vl login <api-key>
|
|
92
|
-
`),process.exit(1));let t=H();t.api_key=e,
|
|
92
|
+
`),process.exit(1));let t=H();t.api_key=e,se(t),console.log(`
|
|
93
93
|
API key saved to ~/.vibelearn/config.json
|
|
94
|
-
`)}async function
|
|
94
|
+
`)}async function ue(){let e=process.argv.slice(2);switch(e[0]){case"-v":case"--version":console.log(`vl ${re}`);break;case"quiz":await le(e.includes("--session"));break;case"status":await ie();break;case"gaps":await ce();break;case"login":{let t=e.includes("--status"),s=t?null:e[1]??null;await ae(s,t);break}default:console.log(`
|
|
95
95
|
VibeLearn CLI \u2014 learn from your coding sessions
|
|
96
96
|
|
|
97
97
|
Usage:
|
|
@@ -101,4 +101,5 @@ Usage:
|
|
|
101
101
|
vl gaps Concepts you haven't mastered yet
|
|
102
102
|
vl login <api-key> Connect to vibelearn.dev
|
|
103
103
|
vl login --status Check login status
|
|
104
|
-
|
|
104
|
+
vl --version Show version
|
|
105
|
+
`)}}ue().catch(e=>{console.error("Error:",e.message),process.exit(1)});
|
|
@@ -247,7 +247,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
247
247
|
`);if(e===-1)return null;let r=this._buffer.toString("utf8",0,e).replace(/\r$/,"");return this._buffer=this._buffer.subarray(e+1),MW(r)}clear(){this._buffer=void 0}};function MW(t){return TR.parse(JSON.parse(t))}function gC(t){return JSON.stringify(t)+`
|
|
248
248
|
`}var LW=Nl.default.platform==="win32"?["APPDATA","HOMEDRIVE","HOMEPATH","LOCALAPPDATA","PATH","PROCESSOR_ARCHITECTURE","SYSTEMDRIVE","SYSTEMROOT","TEMP","USERNAME","USERPROFILE","PROGRAMFILES"]:["HOME","LOGNAME","PATH","SHELL","TERM","USER"];function UW(){let t={};for(let e of LW){let r=Nl.default.env[e];r!==void 0&&(r.startsWith("()")||(t[e]=r))}return t}var Em=class{constructor(e){this._readBuffer=new wm,this._stderrStream=null,this._serverParams=e,(e.stderr==="pipe"||e.stderr==="overlapped")&&(this._stderrStream=new yC.PassThrough)}async start(){if(this._process)throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");return new Promise((e,r)=>{this._process=(0,vC.default)(this._serverParams.command,this._serverParams.args??[],{env:{...UW(),...this._serverParams.env},stdio:["pipe","pipe",this._serverParams.stderr??"inherit"],shell:!1,windowsHide:Nl.default.platform==="win32"&&qW(),cwd:this._serverParams.cwd}),this._process.on("error",n=>{r(n),this.onerror?.(n)}),this._process.on("spawn",()=>{e()}),this._process.on("close",n=>{this._process=void 0,this.onclose?.()}),this._process.stdin?.on("error",n=>{this.onerror?.(n)}),this._process.stdout?.on("data",n=>{this._readBuffer.append(n),this.processReadBuffer()}),this._process.stdout?.on("error",n=>{this.onerror?.(n)}),this._stderrStream&&this._process.stderr&&this._process.stderr.pipe(this._stderrStream)})}get stderr(){return this._stderrStream?this._stderrStream:this._process?.stderr??null}get pid(){return this._process?.pid??null}processReadBuffer(){for(;;)try{let e=this._readBuffer.readMessage();if(e===null)break;this.onmessage?.(e)}catch(e){this.onerror?.(e)}}async close(){if(this._process){let e=this._process;this._process=void 0;let r=new Promise(n=>{e.once("close",()=>{n()})});try{e.stdin?.end()}catch{}if(await Promise.race([r,new Promise(n=>setTimeout(n,2e3).unref())]),e.exitCode===null){try{e.kill("SIGTERM")}catch{}await Promise.race([r,new Promise(n=>setTimeout(n,2e3).unref())])}if(e.exitCode===null)try{e.kill("SIGKILL")}catch{}}this._readBuffer.clear()}send(e){return new Promise(r=>{if(!this._process?.stdin)throw new Error("Not connected");let n=gC(e);this._process.stdin.write(n)?r():this._process.stdin.once("drain",r)})}};function qW(){return"type"in Nl.default}Jr();Tn();kr();var Ua=require("fs"),b0=require("path"),AC=require("os");ie();var u7=(0,b0.join)((0,AC.homedir)(),".vibelearn"),_0=(0,b0.join)(u7,".env"),l7=["ANTHROPIC_API_KEY","CLAUDECODE"];function d7(t){let e={};for(let r of t.split(`
|
|
249
249
|
`)){let n=r.trim();if(!n||n.startsWith("#"))continue;let i=n.indexOf("=");if(i===-1)continue;let s=n.slice(0,i).trim(),o=n.slice(i+1).trim();(o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'"))&&(o=o.slice(1,-1)),s&&(e[s]=o)}return e}function x0(){if(!(0,Ua.existsSync)(_0))return{};try{let t=(0,Ua.readFileSync)(_0,"utf-8"),e=d7(t),r={};return e.ANTHROPIC_API_KEY&&(r.ANTHROPIC_API_KEY=e.ANTHROPIC_API_KEY),e.GEMINI_API_KEY&&(r.GEMINI_API_KEY=e.GEMINI_API_KEY),e.OPENROUTER_API_KEY&&(r.OPENROUTER_API_KEY=e.OPENROUTER_API_KEY),e.VIBELEARN_API_KEY&&(r.VIBELEARN_API_KEY=e.VIBELEARN_API_KEY),r}catch(t){return b.warn("ENV","Failed to load .env file",{path:_0},t),{}}}function jC(t=!0){let e={};for(let[r,n]of Object.entries(process.env))n!==void 0&&!l7.includes(r)&&(e[r]=n);if(e.CLAUDE_CODE_ENTRYPOINT="sdk-ts",t){let r=x0();(process.env.VIBELEARN_CLAUDE_AUTH_METHOD??"cli")==="api"&&r.ANTHROPIC_API_KEY&&(e.ANTHROPIC_API_KEY=r.ANTHROPIC_API_KEY),r.GEMINI_API_KEY&&(e.GEMINI_API_KEY=r.GEMINI_API_KEY),r.OPENROUTER_API_KEY&&(e.OPENROUTER_API_KEY=r.OPENROUTER_API_KEY),!e.ANTHROPIC_API_KEY&&process.env.CLAUDE_CODE_OAUTH_TOKEN&&(e.CLAUDE_CODE_OAUTH_TOKEN=process.env.CLAUDE_CODE_OAUTH_TOKEN)}return e}function qa(t){return x0()[t]}function p7(){return!!x0().ANTHROPIC_API_KEY}function Om(){return p7()?"API key (from ~/.vibelearn/.env)":process.env.CLAUDE_CODE_OAUTH_TOKEN?"Claude Code OAuth token (from parent process)":"Claude Code CLI (subscription billing)"}ie();var mo=require("fs"),GC=require("os"),$0=nt(require("path"),1);ie();var Bi=require("fs"),DC=require("os"),Ml=nt(require("path"),1);ie();var f7=5e3,m7=1e3,h7=Ml.default.join((0,DC.homedir)(),".vibelearn"),g7=Ml.default.join(h7,"supervisor.json");function pn(t){if(!Number.isInteger(t)||t<0||t===0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}var w0=class{registryPath;entries=new Map;runtimeProcesses=new Map;initialized=!1;constructor(e=g7){this.registryPath=e}initialize(){if(this.initialized)return;if(this.initialized=!0,(0,Bi.mkdirSync)(Ml.default.dirname(this.registryPath),{recursive:!0}),!(0,Bi.existsSync)(this.registryPath)){this.persist();return}try{let n=JSON.parse((0,Bi.readFileSync)(this.registryPath,"utf-8")).processes??{};for(let[i,s]of Object.entries(n))this.entries.set(i,s)}catch(r){b.warn("SYSTEM","Failed to parse supervisor registry, rebuilding",{path:this.registryPath},r),this.entries.clear()}let e=this.pruneDeadEntries();e>0&&b.info("SYSTEM","Removed dead processes from supervisor registry",{removed:e}),this.persist()}register(e,r,n){this.initialize(),this.entries.set(e,r),n&&this.runtimeProcesses.set(e,n),this.persist()}unregister(e){this.initialize(),this.entries.delete(e),this.runtimeProcesses.delete(e),this.persist()}clear(){this.entries.clear(),this.runtimeProcesses.clear(),this.persist()}getAll(){return this.initialize(),Array.from(this.entries.entries()).map(([e,r])=>({id:e,...r})).sort((e,r)=>{let n=Date.parse(e.startedAt),i=Date.parse(r.startedAt);return(Number.isNaN(n)?0:n)-(Number.isNaN(i)?0:i)})}getBySession(e){let r=String(e);return this.getAll().filter(n=>n.sessionId!==void 0&&String(n.sessionId)===r)}getRuntimeProcess(e){return this.runtimeProcesses.get(e)}getByPid(e){return this.getAll().filter(r=>r.pid===e)}pruneDeadEntries(){this.initialize();let e=0;for(let[r,n]of this.entries)pn(n.pid)||(this.entries.delete(r),this.runtimeProcesses.delete(r),e+=1);return e>0&&this.persist(),e}async reapSession(e){this.initialize();let r=this.getBySession(e);if(r.length===0)return 0;let n=typeof e=="number"?e:Number(e)||void 0;b.info("SYSTEM",`Reaping ${r.length} process(es) for session ${e}`,{sessionId:n,pids:r.map(a=>a.pid)});let i=r.filter(a=>pn(a.pid));for(let a of i)try{process.kill(a.pid,"SIGTERM")}catch(c){c.code!=="ESRCH"&&b.debug("SYSTEM",`Failed to SIGTERM session process PID ${a.pid}`,{pid:a.pid},c)}let s=Date.now()+f7;for(;Date.now()<s&&i.filter(c=>pn(c.pid)).length!==0;)await new Promise(c=>setTimeout(c,100));let o=i.filter(a=>pn(a.pid));for(let a of o){b.warn("SYSTEM",`Session process PID ${a.pid} did not exit after SIGTERM, sending SIGKILL`,{pid:a.pid,sessionId:n});try{process.kill(a.pid,"SIGKILL")}catch(c){c.code!=="ESRCH"&&b.debug("SYSTEM",`Failed to SIGKILL session process PID ${a.pid}`,{pid:a.pid},c)}}if(o.length>0){let a=Date.now()+m7;for(;Date.now()<a&&o.filter(u=>pn(u.pid)).length!==0;)await new Promise(u=>setTimeout(u,100))}for(let a of r)this.entries.delete(a.id),this.runtimeProcesses.delete(a.id);return this.persist(),b.info("SYSTEM",`Reaped ${r.length} process(es) for session ${e}`,{sessionId:n,reaped:r.length}),r.length}persist(){let e={processes:Object.fromEntries(this.entries.entries())};(0,Bi.mkdirSync)(Ml.default.dirname(this.registryPath),{recursive:!0}),(0,Bi.writeFileSync)(this.registryPath,JSON.stringify(e,null,2))}},S0=null;function Pm(){return S0||(S0=new w0),S0}var LC=require("child_process"),UC=require("fs"),qC=require("os"),E0=nt(require("path"),1),FC=require("util");ie();Tn();var v7=(0,FC.promisify)(LC.execFile),y7=E0.default.join((0,qC.homedir)(),".vibelearn"),_7=E0.default.join(y7,"worker.pid");async function ZC(t){let e=t.currentPid??process.pid,r=t.pidFilePath??_7,n=t.registry.getAll(),i=[...n].filter(o=>o.pid!==e).sort((o,a)=>Date.parse(a.startedAt)-Date.parse(o.startedAt));for(let o of i){if(!pn(o.pid)){t.registry.unregister(o.id);continue}try{await MC(o.pid,"SIGTERM")}catch(a){b.debug("SYSTEM","Failed to send SIGTERM to child process",{pid:o.pid,type:o.type},a)}}await zC(i,5e3);let s=i.filter(o=>pn(o.pid));for(let o of s)try{await MC(o.pid,"SIGKILL")}catch(a){b.debug("SYSTEM","Failed to force kill child process",{pid:o.pid,type:o.type},a)}await zC(s,1e3);for(let o of i)t.registry.unregister(o.id);for(let o of n.filter(a=>a.pid===e))t.registry.unregister(o.id);try{(0,UC.rmSync)(r,{force:!0})}catch(o){b.debug("SYSTEM","Failed to remove PID file during shutdown",{pidFilePath:r},o)}t.registry.pruneDeadEntries()}async function zC(t,e){let r=Date.now()+e;for(;Date.now()<r;){if(t.filter(i=>pn(i.pid)).length===0)return;await new Promise(i=>setTimeout(i,100))}}async function MC(t,e){if(e==="SIGTERM"){try{process.kill(t,e)}catch(r){if(r.code==="ESRCH")return;throw r}return}if(process.platform==="win32"){let r=await b7();if(r){await new Promise((i,s)=>{r(t,e,o=>{if(!o){i();return}if(o.code==="ESRCH"){i();return}s(o)})});return}let n=["/PID",String(t),"/T"];e==="SIGKILL"&&n.push("/F"),await v7("taskkill",n,{timeout:Mr.POWERSHELL_COMMAND,windowsHide:!0});return}try{process.kill(t,e)}catch(r){if(r.code==="ESRCH")return;throw r}}async function b7(){let t="tree-kill";try{let e=await import(t);return e.default??e}catch{return null}}ie();var HC=3e4,Fa=null;function x7(){let e=Pm().pruneDeadEntries();e>0&&b.info("SYSTEM",`Health check: pruned ${e} dead process(es) from registry`)}function BC(){Fa===null&&(Fa=setInterval(x7,HC),Fa.unref(),b.debug("SYSTEM","Health checker started",{intervalMs:HC}))}function VC(){Fa!==null&&(clearInterval(Fa),Fa=null,b.debug("SYSTEM","Health checker stopped"))}var S7=$0.default.join((0,GC.homedir)(),".vibelearn"),w7=$0.default.join(S7,"worker.pid"),k0=class{registry;started=!1;stopPromise=null;signalHandlersRegistered=!1;shutdownInitiated=!1;shutdownHandler=null;constructor(e){this.registry=e}async start(){if(this.started)return;if(this.registry.initialize(),T0({logAlive:!1})==="alive")throw new Error("Worker already running");this.started=!0,BC()}configureSignalHandlers(e){if(this.shutdownHandler=e,this.signalHandlersRegistered)return;this.signalHandlersRegistered=!0;let r=async n=>{if(this.shutdownInitiated){b.warn("SYSTEM",`Received ${n} but shutdown already in progress`);return}this.shutdownInitiated=!0,b.info("SYSTEM",`Received ${n}, shutting down...`);try{this.shutdownHandler?await this.shutdownHandler():await this.stop()}catch(i){b.error("SYSTEM","Error during shutdown",{},i);try{await this.stop()}catch(s){b.debug("SYSTEM","Supervisor shutdown fallback failed",{},s)}}process.exit(0)};process.on("SIGTERM",()=>{r("SIGTERM")}),process.on("SIGINT",()=>{r("SIGINT")}),process.platform!=="win32"&&(process.argv.includes("--daemon")?process.on("SIGHUP",()=>{b.debug("SYSTEM","Ignoring SIGHUP in daemon mode")}):process.on("SIGHUP",()=>{r("SIGHUP")}))}async stop(){if(this.stopPromise){await this.stopPromise;return}VC(),this.stopPromise=ZC({registry:this.registry,currentPid:process.pid}).finally(()=>{this.started=!1,this.stopPromise=null}),await this.stopPromise}assertCanSpawn(e){if(this.stopPromise!==null)throw new Error(`Supervisor is shutting down, refusing to spawn ${e}`)}registerProcess(e,r,n){this.registry.register(e,r,n)}unregisterProcess(e){this.registry.unregister(e)}getRegistry(){return this.registry}},Cm=new k0(Pm());async function WC(){await Cm.start()}async function KC(){await Cm.stop()}function Ft(){return Cm}function JC(t){Cm.configureSignalHandlers(t)}function T0(t={}){let e=t.pidFilePath??w7;if(!(0,mo.existsSync)(e))return"missing";let r=null;try{r=JSON.parse((0,mo.readFileSync)(e,"utf-8"))}catch(n){return b.warn("SYSTEM","Failed to parse worker PID file, removing it",{path:e},n),(0,mo.rmSync)(e,{force:!0}),"invalid"}return pn(r.pid)?((t.logAlive??!0)&&b.info("SYSTEM","Worker already running (PID alive)",{existingPid:r.pid,existingPort:r.port,startedAt:r.startedAt}),"alive"):(b.info("SYSTEM","Removing stale PID file (worker process is dead)",{pid:r.pid,port:r.port,startedAt:r.startedAt}),(0,mo.rmSync)(e,{force:!0}),"stale")}var I0=["CLAUDECODE_","CLAUDE_CODE_"],R0=new Set(["CLAUDECODE","CLAUDE_CODE_SESSION","CLAUDE_CODE_ENTRYPOINT","MCP_SESSION_ID"]);function ks(t=process.env){let e={};for(let[r,n]of Object.entries(t))n!==void 0&&(R0.has(r)||I0.some(i=>r.startsWith(i))||(e[r]=n));return e}var Nm=require("fs"),O0=require("path"),XC=require("os"),E7="vibelearn@anergcorp";function Am(){try{let t=process.env.CLAUDE_CONFIG_DIR||(0,O0.join)((0,XC.homedir)(),".claude"),e=(0,O0.join)(t,"settings.json");if(!(0,Nm.existsSync)(e))return!1;let r=(0,Nm.readFileSync)(e,"utf-8");return JSON.parse(r)?.enabledPlugins?.[E7]===!1}catch{return!1}}var $s=nt(require("path"),1),C0=require("os"),er=require("fs"),Vi=require("child_process"),tN=require("util");ie();Tn();var YC=(0,tN.promisify)(Vi.exec),rN=$s.default.join((0,C0.homedir)(),".vibelearn"),mi=$s.default.join(rN,"worker.pid");var QC=30;function eN(t){return t?/(^|[\\/])bun(\.exe)?$/i.test(t.trim()):!1}function k7(t,e){let r=e==="win32"?`where ${t}`:`which ${t}`;try{return(0,Vi.execSync)(r,{stdio:["ignore","pipe","ignore"],encoding:"utf-8",windowsHide:!0}).split(/\r?\n/).map(s=>s.trim()).find(s=>s.length>0)||null}catch{return null}}function $7(t={}){let e=t.platform??process.platform,r=t.execPath??process.execPath;if(e!=="win32"||eN(r))return r;let n=t.env??process.env,i=t.homeDirectory??(0,C0.homedir)(),s=t.pathExists??er.existsSync,o=t.lookupInPath??k7,a=[n.BUN,n.BUN_PATH,$s.default.join(i,".bun","bin","bun.exe"),$s.default.join(i,".bun","bin","bun"),n.USERPROFILE?$s.default.join(n.USERPROFILE,".bun","bin","bun.exe"):void 0,n.LOCALAPPDATA?$s.default.join(n.LOCALAPPDATA,"bun","bun.exe"):void 0,n.LOCALAPPDATA?$s.default.join(n.LOCALAPPDATA,"bun","bin","bun.exe"):void 0];for(let c of a){let u=c?.trim();if(u&&(eN(u)&&s(u)||u.toLowerCase()==="bun"))return u}return o("bun",e)}function nN(t){(0,er.mkdirSync)(rN,{recursive:!0}),(0,er.writeFileSync)(mi,JSON.stringify(t,null,2))}function N0(){if(!(0,er.existsSync)(mi))return null;try{return JSON.parse((0,er.readFileSync)(mi,"utf-8"))}catch(t){return b.warn("SYSTEM","Failed to parse PID file",{path:mi},t),null}}function ho(){if((0,er.existsSync)(mi))try{(0,er.unlinkSync)(mi)}catch(t){b.warn("SYSTEM","Failed to remove PID file",{path:mi},t)}}function Gi(t){return process.platform==="win32"?Math.round(t*2):t}function T7(t){if(!t||t.trim()==="")return-1;let e=t.trim(),r=0,n=e.match(/^(\d+)-(\d+):(\d+):(\d+)$/);if(n)return r=parseInt(n[1],10)*24*60+parseInt(n[2],10)*60+parseInt(n[3],10),r;let i=e.match(/^(\d+):(\d+):(\d+)$/);if(i)return r=parseInt(i[1],10)*60+parseInt(i[2],10),r;let s=e.match(/^(\d+):(\d+)$/);return s?parseInt(s[1],10):-1}var P0=["worker-service.cjs","chroma-mcp"],I7=["mcp-server.cjs"];async function iN(){let t=process.platform==="win32",e=process.pid,r=[],n=[...P0,...I7];try{if(t){let s=`powershell -NoProfile -NonInteractive -Command "Get-CimInstance Win32_Process -Filter '(${n.map(l=>`CommandLine LIKE '%${l}%'`).join(" OR ")}) AND ProcessId != ${e}' | Select-Object ProcessId, CommandLine, CreationDate | ConvertTo-Json"`,{stdout:o}=await YC(s,{timeout:Mr.POWERSHELL_COMMAND,windowsHide:!0});if(!o.trim()||o.trim()==="null"){b.debug("SYSTEM","No orphaned vibelearn processes found (Windows)");return}let a=JSON.parse(o),c=Array.isArray(a)?a:[a],u=Date.now();for(let l of c){let d=l.ProcessId;if(!Number.isInteger(d)||d<=0||d===e)continue;let p=l.CommandLine||"";if(P0.some(m=>p.includes(m)))r.push(d),b.debug("SYSTEM","Found orphaned process (aggressive)",{pid:d,commandLine:p.substring(0,80)});else{let m=l.CreationDate?.match(/\/Date\((\d+)\)\//);if(m){let g=parseInt(m[1],10),h=(u-g)/(1e3*60);h>=QC&&(r.push(d),b.debug("SYSTEM","Found orphaned process (age-gated)",{pid:d,ageMinutes:Math.round(h)}))}}}}else{let i=n.join("|"),{stdout:s}=await YC(`ps -eo pid,etime,command | grep -E "${i}" | grep -v grep || true`);if(!s.trim()){b.debug("SYSTEM","No orphaned vibelearn processes found (Unix)");return}let o=s.trim().split(`
|
|
250
|
-
`);for(let a of o){let c=a.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!c)continue;let u=parseInt(c[1],10),l=c[2],d=c[3];if(!Number.isInteger(u)||u<=0||u===e)continue;if(P0.some(f=>d.includes(f)))r.push(u),b.debug("SYSTEM","Found orphaned process (aggressive)",{pid:u,command:d.substring(0,80)});else{let f=T7(l);f>=QC&&(r.push(u),b.debug("SYSTEM","Found orphaned process (age-gated)",{pid:u,ageMinutes:f,command:d.substring(0,80)}))}}}}catch(i){b.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},i);return}if(r.length!==0){if(b.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let i of r)if(!(!Number.isInteger(i)||i<=0))try{(0,Vi.execSync)(`taskkill /PID ${i} /T /F`,{timeout:Mr.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(s){b.debug("SYSTEM","Failed to kill process, may have already exited",{pid:i},s)}}else for(let i of r)try{process.kill(i,"SIGKILL")}catch(s){b.debug("SYSTEM","Process already exited",{pid:i},s)}b.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}function A0(t,e,r={}){let n=process.platform==="win32";Ft().assertCanSpawn("worker daemon");let i=ks({...process.env,VIBELEARN_WORKER_PORT:String(e),...r});if(n){let a=$7();if(!a){b.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=a.replace(/'/g,"''"),u=t.replace(/'/g,"''"),l=`Start-Process -FilePath '${c}' -ArgumentList '${u}','--daemon' -WindowStyle Hidden`;try{return(0,Vi.execSync)(`powershell -NoProfile -Command "${l}"`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(d){b.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},d);return}}let s="/usr/bin/setsid";if((0,er.existsSync)(s)){let a=(0,Vi.spawn)(s,[process.execPath,t,"--daemon"],{detached:!0,stdio:"ignore",env:i});return a.pid===void 0?void 0:(a.unref(),a.pid)}let o=(0,Vi.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function sN(t){if(t===0)return!0;if(!Number.isInteger(t)||t<0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function oN(t=15e3){try{let e=(0,er.statSync)(mi);return Date.now()-e.mtimeMs<t}catch{return!1}}function aN(){try{if(!(0,er.existsSync)(mi))return;let t=new Date;(0,er.utimesSync)(mi,t,t)}catch{}}function cN(){return T0({logAlive:!1})}var uN=nt(require("path"),1),lN=require("fs");ie();qt();async function j0(t,e,r="GET"){let n=await fetch(`http://127.0.0.1:${t}${e}`,{method:r}),i="";try{i=await n.text()}catch{}return{ok:n.ok,statusCode:n.status,body:i}}async function Ll(t){try{return(await fetch(`http://127.0.0.1:${t}/api/health`)).ok}catch{return!1}}async function dN(t,e,r,n){let i=Date.now();for(;Date.now()-i<r;){try{if((await j0(t,e)).ok)return!0}catch(s){b.debug("SYSTEM",n,{},s)}await new Promise(s=>setTimeout(s,500))}return!1}function go(t,e=3e4){return dN(t,"/api/health",e,"Service not ready yet, will retry")}function pN(t,e=3e4){return dN(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function jm(t,e=1e4){let r=Date.now();for(;Date.now()-r<e;){if(!await Ll(t))return!0;await new Promise(n=>setTimeout(n,500))}return!1}async function Dm(t){try{let e=await j0(t,"/api/admin/shutdown","POST");return e.ok?!0:(b.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(b.debug("SYSTEM","Worker already stopped",{},e),!1):(b.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}function R7(){try{let t=uN.default.join(Hi,"package.json");return JSON.parse((0,lN.readFileSync)(t,"utf-8")).version}catch(t){let e=t.code;if(e==="ENOENT"||e==="EBUSY")return b.debug("SYSTEM","Could not read plugin version (shutdown race)",{code:e}),"unknown";throw t}}async function O7(t){try{let e=await j0(t,"/api/version");return e.ok?JSON.parse(e.body).version:null}catch{return b.debug("SYSTEM","Could not fetch worker version",{}),null}}async function fN(t){let e=R7(),r=await O7(t);return!r||e==="unknown"?{matches:!0,pluginVersion:e,workerVersion:r}:{matches:e===r,pluginVersion:e,workerVersion:r}}ie();async function mN(t){b.info("SYSTEM","Shutdown initiated"),t.server&&(await P7(t.server),b.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),b.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(b.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),b.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await KC(),b.info("SYSTEM","Worker shutdown complete")}async function P7(t){t.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{t.close(n=>n?r(n):e())}),process.platform==="win32"&&(await new Promise(e=>setTimeout(e,500)),b.info("SYSTEM","Waited for Windows port cleanup"))}var E2=nt(Zh(),1),qE=nt(require("fs"),1),Ed=nt(require("path"),1);var d2=["search","context","summarize","import","export"],p2=["workflow","search_params","examples","all"];ie();var ME=nt(Zh(),1),y2=nt(v2(),1),_2=nt(require("path"),1);qt();ie();function LE(t){let e=[];e.push(ME.default.json({limit:"50mb"})),e.push((0,y2.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(m=>i.path.endsWith(m)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);b.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let f=s.send.bind(s);s.send=function(m){let g=Date.now()-l;return b.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),f(m)},o()});let r=Tr(),n=_2.default.join(r,"plugin","ui");return e.push(ME.default.static(n)),e}function wd(t,e,r){let n=t.ip||t.connection.remoteAddress||"";if(!(n==="127.0.0.1"||n==="::1"||n==="::ffff:127.0.0.1"||n==="localhost")){b.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:n,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function UE(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let n=r.tool_name||"?",i=r.tool_input;return`tool=${b.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}ie();var gc=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function b2(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var x2=(t,e,r,n)=>{let i=t instanceof gc?t.statusCode:500;b.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof gc?t.code:void 0},t);let s=b2(t.name||"Error",t.message,t instanceof gc?t.code:void 0,t instanceof gc?t.details:void 0);r.status(i).json(s)};function S2(t,e){e.status(404).json(b2("NotFound",`Cannot ${t.method} ${t.path}`))}var w2="0.1.3",Hh=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,E2.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,i)=>{this.server=this.app.listen(e,r,()=>{b.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()}),this.server.on("error",i)})}async close(){this.server&&(this.server.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{this.server.close(n=>n?r(n):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,b.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(S2),this.app.use(x2)}setupMiddleware(){LE(UE).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:w2,workerPath:this.options.workerPath,uptime:Date.now()-this.startTime,managed:process.env.VIBELEARN_MANAGED==="true",hasIpc:typeof process.send=="function",platform:process.platform,pid:process.pid,initialized:this.options.getInitializationComplete(),mcpReady:this.options.getMcpReady(),ai:this.options.getAiStatus()})}),this.app.get("/api/readiness",(e,r)=>{this.options.getInitializationComplete()?r.status(200).json({status:"ready",mcpReady:this.options.getMcpReady()}):r.status(503).json({status:"initializing",message:"Worker is still initializing, please retry"})}),this.app.get("/api/version",(e,r)=>{r.status(200).json({version:w2})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!p2.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!d2.includes(i))return r.status(400).json({error:"Invalid operation"});let o=Ed.default.resolve(__dirname,"../skills/mem-search/operations"),a=Ed.default.resolve(o,`${i}.md`);if(!a.startsWith(o+Ed.default.sep))return r.status(400).json({error:"Invalid request"});s=await qE.promises.readFile(a,"utf-8")}else{let o=Ed.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await qE.promises.readFile(o,"utf-8");s=this.extractInstructionSection(a,n)}r.json({content:[{type:"text",text:s}]})}catch{r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",wd,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.VIBELEARN_MANAGED==="true"&&process.send?(b.info("SYSTEM","Sending restart request to wrapper"),process.send({type:"restart"})):setTimeout(async()=>{try{await this.options.onRestart()}finally{process.exit(0)}},100)}),this.app.post("/api/admin/shutdown",wd,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.VIBELEARN_MANAGED==="true"&&process.send?(b.info("SYSTEM","Sending shutdown request to wrapper"),process.send({type:"shutdown"})):setTimeout(async()=>{try{await this.options.onShutdown()}finally{process.exit(0)}},100)}),this.app.get("/api/admin/doctor",wd,(e,r)=>{let o=Ft().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:pn(m.pid)?"alive":"dead",startedAt:m.startedAt})),a=o.filter(m=>m.status==="dead").map(m=>m.pid),c=!Object.keys(process.env).some(m=>R0.has(m)||I0.some(g=>m.startsWith(g))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),f=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:f},processes:o,health:{deadProcessPids:a,envClean:c}})})}extractInstructionSection(e,r){let n={workflow:this.extractBetween(e,"## The Workflow","## Search Parameters"),search_params:this.extractBetween(e,"## Search Parameters","## Examples"),examples:this.extractBetween(e,"## Examples","## Why This Workflow"),all:e};return n[r]||n.all}extractBetween(e,r,n){let i=e.indexOf(r),s=e.indexOf(n);return i===-1?e:s===-1?e.substring(i):e.substring(i,s).trim()}};var mt=nt(require("path"),1),$d=require("os"),Bt=require("fs"),T2=require("child_process"),I2=require("util");ie();Jr();qt();var Nn=require("fs"),kd=require("path");ie();function k2(t){try{return(0,Nn.existsSync)(t)?JSON.parse((0,Nn.readFileSync)(t,"utf-8")):{}}catch(e){return b.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function $2(t,e){let r=(0,kd.join)(t,"..");(0,Nn.mkdirSync)(r,{recursive:!0}),(0,Nn.writeFileSync)(t,JSON.stringify(e,null,2))}function FE(t,e){let r=(0,kd.join)(t,".cursor","rules"),n=(0,kd.join)(r,"vibelearn-context.mdc"),i=`${n}.tmp`;(0,Nn.mkdirSync)(r,{recursive:!0});let s=`---
|
|
250
|
+
`);for(let a of o){let c=a.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!c)continue;let u=parseInt(c[1],10),l=c[2],d=c[3];if(!Number.isInteger(u)||u<=0||u===e)continue;if(P0.some(f=>d.includes(f)))r.push(u),b.debug("SYSTEM","Found orphaned process (aggressive)",{pid:u,command:d.substring(0,80)});else{let f=T7(l);f>=QC&&(r.push(u),b.debug("SYSTEM","Found orphaned process (age-gated)",{pid:u,ageMinutes:f,command:d.substring(0,80)}))}}}}catch(i){b.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},i);return}if(r.length!==0){if(b.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let i of r)if(!(!Number.isInteger(i)||i<=0))try{(0,Vi.execSync)(`taskkill /PID ${i} /T /F`,{timeout:Mr.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(s){b.debug("SYSTEM","Failed to kill process, may have already exited",{pid:i},s)}}else for(let i of r)try{process.kill(i,"SIGKILL")}catch(s){b.debug("SYSTEM","Process already exited",{pid:i},s)}b.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}function A0(t,e,r={}){let n=process.platform==="win32";Ft().assertCanSpawn("worker daemon");let i=ks({...process.env,VIBELEARN_WORKER_PORT:String(e),...r});if(n){let a=$7();if(!a){b.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=a.replace(/'/g,"''"),u=t.replace(/'/g,"''"),l=`Start-Process -FilePath '${c}' -ArgumentList '${u}','--daemon' -WindowStyle Hidden`;try{return(0,Vi.execSync)(`powershell -NoProfile -Command "${l}"`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(d){b.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},d);return}}let s="/usr/bin/setsid";if((0,er.existsSync)(s)){let a=(0,Vi.spawn)(s,[process.execPath,t,"--daemon"],{detached:!0,stdio:"ignore",env:i});return a.pid===void 0?void 0:(a.unref(),a.pid)}let o=(0,Vi.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function sN(t){if(t===0)return!0;if(!Number.isInteger(t)||t<0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function oN(t=15e3){try{let e=(0,er.statSync)(mi);return Date.now()-e.mtimeMs<t}catch{return!1}}function aN(){try{if(!(0,er.existsSync)(mi))return;let t=new Date;(0,er.utimesSync)(mi,t,t)}catch{}}function cN(){return T0({logAlive:!1})}var uN=nt(require("path"),1),lN=require("fs");ie();qt();async function j0(t,e,r="GET"){let n=await fetch(`http://127.0.0.1:${t}${e}`,{method:r}),i="";try{i=await n.text()}catch{}return{ok:n.ok,statusCode:n.status,body:i}}async function Ll(t){try{return(await fetch(`http://127.0.0.1:${t}/api/health`)).ok}catch{return!1}}async function dN(t,e,r,n){let i=Date.now();for(;Date.now()-i<r;){try{if((await j0(t,e)).ok)return!0}catch(s){b.debug("SYSTEM",n,{},s)}await new Promise(s=>setTimeout(s,500))}return!1}function go(t,e=3e4){return dN(t,"/api/health",e,"Service not ready yet, will retry")}function pN(t,e=3e4){return dN(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function jm(t,e=1e4){let r=Date.now();for(;Date.now()-r<e;){if(!await Ll(t))return!0;await new Promise(n=>setTimeout(n,500))}return!1}async function Dm(t){try{let e=await j0(t,"/api/admin/shutdown","POST");return e.ok?!0:(b.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(b.debug("SYSTEM","Worker already stopped",{},e),!1):(b.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}function R7(){try{let t=uN.default.join(Hi,"package.json");return JSON.parse((0,lN.readFileSync)(t,"utf-8")).version}catch(t){let e=t.code;if(e==="ENOENT"||e==="EBUSY")return b.debug("SYSTEM","Could not read plugin version (shutdown race)",{code:e}),"unknown";throw t}}async function O7(t){try{let e=await j0(t,"/api/version");return e.ok?JSON.parse(e.body).version:null}catch{return b.debug("SYSTEM","Could not fetch worker version",{}),null}}async function fN(t){let e=R7(),r=await O7(t);return!r||e==="unknown"?{matches:!0,pluginVersion:e,workerVersion:r}:{matches:e===r,pluginVersion:e,workerVersion:r}}ie();async function mN(t){b.info("SYSTEM","Shutdown initiated"),t.server&&(await P7(t.server),b.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),b.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(b.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),b.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await KC(),b.info("SYSTEM","Worker shutdown complete")}async function P7(t){t.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{t.close(n=>n?r(n):e())}),process.platform==="win32"&&(await new Promise(e=>setTimeout(e,500)),b.info("SYSTEM","Waited for Windows port cleanup"))}var E2=nt(Zh(),1),qE=nt(require("fs"),1),Ed=nt(require("path"),1);var d2=["search","context","summarize","import","export"],p2=["workflow","search_params","examples","all"];ie();var ME=nt(Zh(),1),y2=nt(v2(),1),_2=nt(require("path"),1);qt();ie();function LE(t){let e=[];e.push(ME.default.json({limit:"50mb"})),e.push((0,y2.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(m=>i.path.endsWith(m)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);b.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let f=s.send.bind(s);s.send=function(m){let g=Date.now()-l;return b.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),f(m)},o()});let r=Tr(),n=_2.default.join(r,"plugin","ui");return e.push(ME.default.static(n)),e}function wd(t,e,r){let n=t.ip||t.connection.remoteAddress||"";if(!(n==="127.0.0.1"||n==="::1"||n==="::ffff:127.0.0.1"||n==="localhost")){b.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:n,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function UE(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let n=r.tool_name||"?",i=r.tool_input;return`tool=${b.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}ie();var gc=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function b2(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var x2=(t,e,r,n)=>{let i=t instanceof gc?t.statusCode:500;b.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof gc?t.code:void 0},t);let s=b2(t.name||"Error",t.message,t instanceof gc?t.code:void 0,t instanceof gc?t.details:void 0);r.status(i).json(s)};function S2(t,e){e.status(404).json(b2("NotFound",`Cannot ${t.method} ${t.path}`))}var w2="0.1.4",Hh=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,E2.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,i)=>{this.server=this.app.listen(e,r,()=>{b.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()}),this.server.on("error",i)})}async close(){this.server&&(this.server.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{this.server.close(n=>n?r(n):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,b.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(S2),this.app.use(x2)}setupMiddleware(){LE(UE).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:w2,workerPath:this.options.workerPath,uptime:Date.now()-this.startTime,managed:process.env.VIBELEARN_MANAGED==="true",hasIpc:typeof process.send=="function",platform:process.platform,pid:process.pid,initialized:this.options.getInitializationComplete(),mcpReady:this.options.getMcpReady(),ai:this.options.getAiStatus()})}),this.app.get("/api/readiness",(e,r)=>{this.options.getInitializationComplete()?r.status(200).json({status:"ready",mcpReady:this.options.getMcpReady()}):r.status(503).json({status:"initializing",message:"Worker is still initializing, please retry"})}),this.app.get("/api/version",(e,r)=>{r.status(200).json({version:w2})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!p2.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!d2.includes(i))return r.status(400).json({error:"Invalid operation"});let o=Ed.default.resolve(__dirname,"../skills/mem-search/operations"),a=Ed.default.resolve(o,`${i}.md`);if(!a.startsWith(o+Ed.default.sep))return r.status(400).json({error:"Invalid request"});s=await qE.promises.readFile(a,"utf-8")}else{let o=Ed.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await qE.promises.readFile(o,"utf-8");s=this.extractInstructionSection(a,n)}r.json({content:[{type:"text",text:s}]})}catch{r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",wd,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.VIBELEARN_MANAGED==="true"&&process.send?(b.info("SYSTEM","Sending restart request to wrapper"),process.send({type:"restart"})):setTimeout(async()=>{try{await this.options.onRestart()}finally{process.exit(0)}},100)}),this.app.post("/api/admin/shutdown",wd,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.VIBELEARN_MANAGED==="true"&&process.send?(b.info("SYSTEM","Sending shutdown request to wrapper"),process.send({type:"shutdown"})):setTimeout(async()=>{try{await this.options.onShutdown()}finally{process.exit(0)}},100)}),this.app.get("/api/admin/doctor",wd,(e,r)=>{let o=Ft().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:pn(m.pid)?"alive":"dead",startedAt:m.startedAt})),a=o.filter(m=>m.status==="dead").map(m=>m.pid),c=!Object.keys(process.env).some(m=>R0.has(m)||I0.some(g=>m.startsWith(g))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),f=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:f},processes:o,health:{deadProcessPids:a,envClean:c}})})}extractInstructionSection(e,r){let n={workflow:this.extractBetween(e,"## The Workflow","## Search Parameters"),search_params:this.extractBetween(e,"## Search Parameters","## Examples"),examples:this.extractBetween(e,"## Examples","## Why This Workflow"),all:e};return n[r]||n.all}extractBetween(e,r,n){let i=e.indexOf(r),s=e.indexOf(n);return i===-1?e:s===-1?e.substring(i):e.substring(i,s).trim()}};var mt=nt(require("path"),1),$d=require("os"),Bt=require("fs"),T2=require("child_process"),I2=require("util");ie();Jr();qt();var Nn=require("fs"),kd=require("path");ie();function k2(t){try{return(0,Nn.existsSync)(t)?JSON.parse((0,Nn.readFileSync)(t,"utf-8")):{}}catch(e){return b.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function $2(t,e){let r=(0,kd.join)(t,"..");(0,Nn.mkdirSync)(r,{recursive:!0}),(0,Nn.writeFileSync)(t,JSON.stringify(e,null,2))}function FE(t,e){let r=(0,kd.join)(t,".cursor","rules"),n=(0,kd.join)(r,"vibelearn-context.mdc"),i=`${n}.tmp`;(0,Nn.mkdirSync)(r,{recursive:!0});let s=`---
|
|
251
251
|
alwaysApply: true
|
|
252
252
|
description: "VibeLearn context from past sessions (auto-updated)"
|
|
253
253
|
---
|
|
@@ -1524,7 +1524,7 @@ Respond ONLY with this XML (no other text):
|
|
|
1524
1524
|
FROM observations
|
|
1525
1525
|
WHERE memory_session_id = ?
|
|
1526
1526
|
AND type IN (?, ?)
|
|
1527
|
-
`).get(e,"file_write","file_edit")?.count??0}function rq(t,e){return mhe(t,e)>=
|
|
1527
|
+
`).get(e,"file_write","file_edit")?.count??0}function rq(t,e){return mhe(t,e)>=2}var ghe="https://generativelanguage.googleapis.com/v1/models",vhe="https://openrouter.ai/api/v1/chat/completions",yhe="https://api.anthropic.com/v1/messages";function nq(){let t=Re.loadFromFile(Qt),e=t.VIBELEARN_GEMINI_API_KEY||process.env.GEMINI_API_KEY||"";if(e)return async i=>{let s=`${ghe}/gemini-2.0-flash:generateContent?key=${e}`,o=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contents:[{role:"user",parts:[{text:i}]}],generationConfig:{temperature:.2,maxOutputTokens:8192}})});if(!o.ok)throw new Error(`Gemini API error: ${o.status}`);return(await o.json()).candidates?.[0]?.content?.parts?.[0]?.text??""};let r=t.VIBELEARN_OPENROUTER_API_KEY||process.env.OPENROUTER_API_KEY||"";if(r){let i=t.VIBELEARN_OPENROUTER_MODEL||"mistralai/mistral-7b-instruct";return async s=>{let o=await fetch(vhe,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({model:i,messages:[{role:"user",content:s}],temperature:.2,max_tokens:8192})});if(!o.ok)throw new Error(`OpenRouter API error: ${o.status}`);return(await o.json()).choices?.[0]?.message?.content??""}}let n=process.env.ANTHROPIC_API_KEY||"";if(!n)try{let i=(0,pp.join)(Re.get("VIBELEARN_DATA_DIR"),".env");if((0,fp.existsSync)(i)){let o=(0,fp.readFileSync)(i,"utf-8").match(/^ANTHROPIC_API_KEY=(.+)$/m);o&&(n=o[1].trim())}}catch{}return async i=>{let s=await fetch(yhe,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":n,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:"claude-haiku-4-5-20251001",max_tokens:8192,temperature:.2,messages:[{role:"user",content:i}]})});if(!s.ok)throw new Error(`Anthropic API error: ${s.status}`);return(await s.json()).content?.[0]?.text??""}}function nv(t,e){return t.query(`
|
|
1528
1528
|
SELECT id, content_session_id, memory_session_id, project, started_at_epoch
|
|
1529
1529
|
FROM sdk_sessions
|
|
1530
1530
|
WHERE content_session_id = ?
|
|
@@ -1537,7 +1537,7 @@ Respond ONLY with this XML (no other text):
|
|
|
1537
1537
|
INSERT OR REPLACE INTO vl_stack_profiles
|
|
1538
1538
|
(session_id, language_json, framework, orm, state_management, testing_json, auth, styling_json, confidence_json)
|
|
1539
1539
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1540
|
-
`,[i,u.language_json,u.framework,u.orm,u.state_management,u.testing_json,u.auth,u.styling_json,u.confidence_json]),b.info("VL","Stack detected",{sessionId:i,framework:u.framework,languages:u.language_json}),n.json({status:"ok",stack:u})}async handleStatic(r,n){let{contentSessionId:i}=r.body;if(!i)return this.badRequest(n,"Missing contentSessionId");let s=this.dbManager.getSessionStore().db,o=nv(s,i);if(!o)return this.notFound(n,"Session not found");let a=Kk(s,o.memory_session_id),c=iq(a),u=Gk(c);b.info("VL","Static analysis complete",{sessionId:i,files:c.length,patterns:u.length}),n.json({status:"ok",patterns_count:u.length})}async handleConcepts(r,n){let{contentSessionId:i,last_assistant_message:s}=r.body;if(!i)return this.badRequest(n,"Missing contentSessionId");let o=this.dbManager.getSessionStore().db,a=nv(o,i);if(!a)return this.notFound(n,"Session not found");if(a.memory_session_id&&!rq(o,a.memory_session_id)){b.info("VL","Skipping concept extraction \u2014 insufficient write observations",{sessionId:i,required:
|
|
1540
|
+
`,[i,u.language_json,u.framework,u.orm,u.state_management,u.testing_json,u.auth,u.styling_json,u.confidence_json]),b.info("VL","Stack detected",{sessionId:i,framework:u.framework,languages:u.language_json}),n.json({status:"ok",stack:u})}async handleStatic(r,n){let{contentSessionId:i}=r.body;if(!i)return this.badRequest(n,"Missing contentSessionId");let s=this.dbManager.getSessionStore().db,o=nv(s,i);if(!o)return this.notFound(n,"Session not found");let a=Kk(s,o.memory_session_id),c=iq(a),u=Gk(c);b.info("VL","Static analysis complete",{sessionId:i,files:c.length,patterns:u.length}),n.json({status:"ok",patterns_count:u.length})}async handleConcepts(r,n){let{contentSessionId:i,last_assistant_message:s}=r.body;if(!i)return this.badRequest(n,"Missing contentSessionId");let o=this.dbManager.getSessionStore().db,a=nv(o,i);if(!a)return this.notFound(n,"Session not found");if(a.memory_session_id&&!rq(o,a.memory_session_id)){b.info("VL","Skipping concept extraction \u2014 insufficient write observations",{sessionId:i,required:2}),n.json({status:"skipped",reason:"insufficient_observations"});return}let c=o.query(`
|
|
1541
1541
|
SELECT * FROM vl_stack_profiles WHERE session_id = ? LIMIT 1
|
|
1542
1542
|
`).get(i)??{session_id:i,language_json:"[]",framework:null,orm:null,state_management:null,testing_json:"[]",auth:null,styling_json:"[]",confidence_json:"{}"},u=Kk(o,a.memory_session_id),l=iq(u),d=Gk(l),p=Math.max(1,Math.round((Date.now()-a.started_at_epoch)/6e4)),f=(0,pp.basename)(a.project),m=nq(),{summary:g,concepts:h}=await BU(i,f,s??"",c,d,{created:0,edited:u.length},p,m);o.run(`
|
|
1543
1543
|
INSERT OR REPLACE INTO vibelearn_session_summaries
|
|
@@ -1592,7 +1592,7 @@ Respond ONLY with this XML (no other text):
|
|
|
1592
1592
|
FROM vl_concepts
|
|
1593
1593
|
WHERE session_id = ?
|
|
1594
1594
|
ORDER BY confidence DESC
|
|
1595
|
-
`).all(i);n.json({summary:o,concepts:a})}};var Khe={},qhe=120*1e3;function m$(){return f$.default.join(Re.get("VIBELEARN_DATA_DIR"),".worker-start-attempted")}function Fhe(){if(process.platform!=="win32")return!1;let t=m$();if(!(0,os.existsSync)(t))return!1;try{let e=(0,os.statSync)(t).mtimeMs;return Date.now()-e<qhe}catch{return!1}}function Zhe(){if(process.platform==="win32")try{(0,os.writeFileSync)(m$(),"","utf-8")}catch{}}function Hhe(){if(process.platform==="win32")try{let t=m$();(0,os.existsSync)(t)&&(0,os.unlinkSync)(t)}catch{}}var Bhe="0.1.3";function Aq(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var av=class{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;searchRoutes=null;initializationComplete;resolveInitialization;stopOrphanReaper=null;staleSessionReaperInterval=null;lastAiInteraction=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new Kh,this.sessionManager=new Qh(this.dbManager),this.sseBroadcaster=new eg,this.sdkAgent=new Pg(this.dbManager,this.sessionManager),this.geminiAgent=new Cg(this.dbManager,this.sessionManager),this.openRouterAgent=new jg(this.dbManager,this.sessionManager),this.paginationHelper=new Dg(this.dbManager),this.settingsManager=new zg(this.dbManager),this.sessionEventBroadcaster=new qg(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new xm({name:"worker-search-proxy",version:Bhe},{capabilities:{}}),this.server=new Hh({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return Gc()&&Zo()?e="openrouter":Vc()&&Fo()&&(e="gemini"),{provider:e,authMethod:Om(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){JC(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){b.warn("SYSTEM","Context requested before initialization complete, returning empty"),r.status(200).json({content:[{type:"text",text:""}]});return}n()}),this.server.app.use("/api",async(e,r,n)=>{if(this.initializationCompleteFlag){n();return}let i=3e4,s=new Promise((o,a)=>setTimeout(()=>a(new Error("Database initialization timeout")),i));try{await Promise.race([this.initializationComplete,s]),n()}catch(o){b.error("HTTP",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized`,{},o),r.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"})}}),this.server.registerRoutes(new Zg(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new Vg(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new Gg(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new Xg(this.settingsManager)),this.server.registerRoutes(new Qg),this.server.registerRoutes(new ev(this.dbManager,"vibelearn")),this.server.registerRoutes(new iv(this.dbManager))}async start(){let e=dn(),r=y0();await WC(),await this.server.listen(e,r),nN({pid:process.pid,port:e,startedAt:new Date().toISOString()}),Ft().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),b.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{b.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await iN();let{ModeManager:e}=await Promise.resolve().then(()=>(Xn(),G2)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(kr(),wC)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(qt(),PC)),i=r.loadFromFile(n),s="code";e.getInstance().loadMode(s),b.info("SYSTEM",`Mode loaded: ${s}`),await this.dbManager.initialize();let{PendingMessageStore:o}=await Promise.resolve().then(()=>(js(),Ao)),c=new o(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);c>0&&b.info("SYSTEM",`Reset ${c} stale processing messages to pending`);let u=new Lg,l=new Ug,d=new Mg(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),u,l);this.searchRoutes=new Wg(d),this.server.registerRoutes(this.searchRoutes),b.info("WORKER","SearchManager initialized and search routes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),b.info("SYSTEM","Core initialization complete (DB + search ready)");let p=f$.default.join(__dirname,"mcp-server.cjs");Ft().assertCanSpawn("mcp server");let f=new Em({command:"node",args:[p],env:ks(process.env)}),m=3e5,g=this.mcpClient.connect(f),h,v=new Promise((y,x)=>{h=setTimeout(()=>x(new Error("MCP connection timeout after 5 minutes")),m)});try{await Promise.race([g,v])}catch(y){clearTimeout(h),b.warn("WORKER","MCP server connection failed, cleaning up subprocess",{error:y instanceof Error?y.message:String(y)});try{await f.close()}catch{}throw y}clearTimeout(h);let _=f._process;_?.pid&&(Ft().registerProcess("mcp-server",{pid:_.pid,type:"mcp",startedAt:new Date().toISOString()},_),_.once("exit",()=>{Ft().unregisterProcess("mcp-server")})),this.mcpReady=!0,b.success("WORKER","MCP server connected"),this.stopOrphanReaper=B2(()=>{let y=new Set;for(let[x]of this.sessionManager.sessions)y.add(x);return y}),b.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let y=await this.sessionManager.reapStaleSessions();y>0&&b.info("SYSTEM",`Reaped ${y} stale sessions`)}catch(y){b.error("SYSTEM","Stale session reaper error",{error:y instanceof Error?y.message:String(y)})}},120*1e3),this.processPendingQueues(50).then(y=>{y.sessionsStarted>0&&b.info("SYSTEM",`Auto-recovered ${y.sessionsStarted} sessions with pending work`,{totalPending:y.totalPendingSessions,started:y.sessionsStarted,sessionIds:y.startedSessionIds})}).catch(y=>{b.error("SYSTEM","Auto-recovery of pending queues failed",{},y)})}catch(e){throw b.error("SYSTEM","Background initialization failed",{},e),e}}getActiveAgent(){return Gc()&&Zo()?this.openRouterAgent:Vc()&&Fo()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let n=e.sessionDbId,i=this.getActiveAgent(),s=i.constructor.name;e.abortController.signal.aborted&&(b.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;b.info("SYSTEM",`Starting generator (${r}) using ${s}`,{sessionId:n}),e.lastGeneratorActivity=Date.now(),e.generatorPromise=i.startSession(e,this).catch(async c=>{let u=c?.message||"";if(["Claude executable not found","CLAUDE_CODE_PATH","ENOENT","spawn","Invalid API key","FOREIGN KEY constraint failed"].some(d=>u.includes(d))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},b.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return b.warn("SDK","SDK resume failed, falling back to standalone processing",{sessionId:e.sessionDbId,project:e.project,reason:c instanceof Error?c.message:String(c)}),this.runFallbackForTerminatedSession(e,c);throw(u.includes("aborted by user")||u.includes("No conversation found"))&&e.memorySessionId&&(b.warn("SDK","Detected stale resume failure, clearing memorySessionId for fresh start",{sessionId:e.sessionDbId,memorySessionId:e.memorySessionId,errorMessage:u}),this.dbManager.getSessionStore().updateMemorySessionId(e.sessionDbId,null),e.memorySessionId=null,e.forceInit=!0),b.error("SDK","Session generator failed",{sessionId:e.sessionDbId,project:e.project,provider:s},c),a=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},c}).finally(async()=>{let c=Ds(e.sessionDbId);if(c&&c.process.exitCode===null&&await zs(c,5e3),e.generatorPromise=null,!a&&!o&&(this.lastAiInteraction={timestamp:Date.now(),success:!0,provider:s}),o){b.warn("SYSTEM","Skipping restart due to unrecoverable error",{sessionId:e.sessionDbId}),this.broadcastProcessingStatus();return}let{PendingMessageStore:u}=(js(),Xc(Ao)),l=new u(this.dbManager.getSessionStore().db,3);if(e.idleTimedOut){b.info("SYSTEM","Generator exited due to idle timeout, not restarting",{sessionId:e.sessionDbId}),e.idleTimedOut=!1,this.broadcastProcessingStatus();return}let d=l.getPendingCount(e.sessionDbId),p=3;if(d>0){if(e.consecutiveRestarts=(e.consecutiveRestarts||0)+1,e.consecutiveRestarts>p){b.error("SYSTEM","Exceeded max pending-work restarts, stopping to prevent infinite loop",{sessionId:e.sessionDbId,pendingCount:d,consecutiveRestarts:e.consecutiveRestarts}),e.consecutiveRestarts=0,this.broadcastProcessingStatus();return}b.info("SYSTEM","Pending work remains after generator exit, restarting with fresh AbortController",{sessionId:e.sessionDbId,pendingCount:d,attempt:e.consecutiveRestarts}),e.abortController=new AbortController,this.startSessionProcessor(e,"pending-work-restart")}else e.consecutiveRestarts=0;this.broadcastProcessingStatus()})}isSessionTerminatedError(e){let n=(e instanceof Error?e.message:String(e)).toLowerCase();return n.includes("process aborted by user")||n.includes("processtransport")||n.includes("not ready for writing")||n.includes("session generator failed")||n.includes("claude code process")}async runFallbackForTerminatedSession(e,r){if(!e)return;let n=e.sessionDbId;if(!e.memorySessionId){let o=`fallback-${n}-${Date.now()}`;e.memorySessionId=o,this.dbManager.getSessionStore().updateMemorySessionId(n,o)}if(Fo())try{await this.geminiAgent.startSession(e,this);return}catch(o){b.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:o instanceof Error?o.message:String(o)})}if(Zo())try{await this.openRouterAgent.startSession(e,this);return}catch(o){b.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:o instanceof Error?o.message:String(o)})}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&b.warn("SDK","No fallback available; marked pending messages abandoned",{sessionId:n,abandoned:s}),this.sessionManager.removeSessionImmediate(n),this.sessionEventBroadcaster.broadcastSessionCompleted(n)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(js(),Ao)),n=new r(this.dbManager.getSessionStore().db,3),i=this.dbManager.getSessionStore(),s=360*60*1e3,o=Date.now()-s;try{let u=i.db.prepare(`
|
|
1595
|
+
`).all(i);n.json({summary:o,concepts:a})}};var Khe={},qhe=120*1e3;function m$(){return f$.default.join(Re.get("VIBELEARN_DATA_DIR"),".worker-start-attempted")}function Fhe(){if(process.platform!=="win32")return!1;let t=m$();if(!(0,os.existsSync)(t))return!1;try{let e=(0,os.statSync)(t).mtimeMs;return Date.now()-e<qhe}catch{return!1}}function Zhe(){if(process.platform==="win32")try{(0,os.writeFileSync)(m$(),"","utf-8")}catch{}}function Hhe(){if(process.platform==="win32")try{let t=m$();(0,os.existsSync)(t)&&(0,os.unlinkSync)(t)}catch{}}var Bhe="0.1.4";function Aq(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var av=class{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;searchRoutes=null;initializationComplete;resolveInitialization;stopOrphanReaper=null;staleSessionReaperInterval=null;lastAiInteraction=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new Kh,this.sessionManager=new Qh(this.dbManager),this.sseBroadcaster=new eg,this.sdkAgent=new Pg(this.dbManager,this.sessionManager),this.geminiAgent=new Cg(this.dbManager,this.sessionManager),this.openRouterAgent=new jg(this.dbManager,this.sessionManager),this.paginationHelper=new Dg(this.dbManager),this.settingsManager=new zg(this.dbManager),this.sessionEventBroadcaster=new qg(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new xm({name:"worker-search-proxy",version:Bhe},{capabilities:{}}),this.server=new Hh({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return Gc()&&Zo()?e="openrouter":Vc()&&Fo()&&(e="gemini"),{provider:e,authMethod:Om(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){JC(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){b.warn("SYSTEM","Context requested before initialization complete, returning empty"),r.status(200).json({content:[{type:"text",text:""}]});return}n()}),this.server.app.use("/api",async(e,r,n)=>{if(this.initializationCompleteFlag){n();return}let i=3e4,s=new Promise((o,a)=>setTimeout(()=>a(new Error("Database initialization timeout")),i));try{await Promise.race([this.initializationComplete,s]),n()}catch(o){b.error("HTTP",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized`,{},o),r.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"})}}),this.server.registerRoutes(new Zg(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new Vg(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new Gg(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new Xg(this.settingsManager)),this.server.registerRoutes(new Qg),this.server.registerRoutes(new ev(this.dbManager,"vibelearn")),this.server.registerRoutes(new iv(this.dbManager))}async start(){let e=dn(),r=y0();await WC(),await this.server.listen(e,r),nN({pid:process.pid,port:e,startedAt:new Date().toISOString()}),Ft().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),b.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{b.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await iN();let{ModeManager:e}=await Promise.resolve().then(()=>(Xn(),G2)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(kr(),wC)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(qt(),PC)),i=r.loadFromFile(n),s="code";e.getInstance().loadMode(s),b.info("SYSTEM",`Mode loaded: ${s}`),await this.dbManager.initialize();let{PendingMessageStore:o}=await Promise.resolve().then(()=>(js(),Ao)),c=new o(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);c>0&&b.info("SYSTEM",`Reset ${c} stale processing messages to pending`);let u=new Lg,l=new Ug,d=new Mg(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),u,l);this.searchRoutes=new Wg(d),this.server.registerRoutes(this.searchRoutes),b.info("WORKER","SearchManager initialized and search routes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),b.info("SYSTEM","Core initialization complete (DB + search ready)");let p=f$.default.join(__dirname,"mcp-server.cjs");Ft().assertCanSpawn("mcp server");let f=new Em({command:"node",args:[p],env:ks(process.env)}),m=3e5,g=this.mcpClient.connect(f),h,v=new Promise((y,x)=>{h=setTimeout(()=>x(new Error("MCP connection timeout after 5 minutes")),m)});try{await Promise.race([g,v])}catch(y){clearTimeout(h),b.warn("WORKER","MCP server connection failed, cleaning up subprocess",{error:y instanceof Error?y.message:String(y)});try{await f.close()}catch{}throw y}clearTimeout(h);let _=f._process;_?.pid&&(Ft().registerProcess("mcp-server",{pid:_.pid,type:"mcp",startedAt:new Date().toISOString()},_),_.once("exit",()=>{Ft().unregisterProcess("mcp-server")})),this.mcpReady=!0,b.success("WORKER","MCP server connected"),this.stopOrphanReaper=B2(()=>{let y=new Set;for(let[x]of this.sessionManager.sessions)y.add(x);return y}),b.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let y=await this.sessionManager.reapStaleSessions();y>0&&b.info("SYSTEM",`Reaped ${y} stale sessions`)}catch(y){b.error("SYSTEM","Stale session reaper error",{error:y instanceof Error?y.message:String(y)})}},120*1e3),this.processPendingQueues(50).then(y=>{y.sessionsStarted>0&&b.info("SYSTEM",`Auto-recovered ${y.sessionsStarted} sessions with pending work`,{totalPending:y.totalPendingSessions,started:y.sessionsStarted,sessionIds:y.startedSessionIds})}).catch(y=>{b.error("SYSTEM","Auto-recovery of pending queues failed",{},y)})}catch(e){throw b.error("SYSTEM","Background initialization failed",{},e),e}}getActiveAgent(){return Gc()&&Zo()?this.openRouterAgent:Vc()&&Fo()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let n=e.sessionDbId,i=this.getActiveAgent(),s=i.constructor.name;e.abortController.signal.aborted&&(b.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;b.info("SYSTEM",`Starting generator (${r}) using ${s}`,{sessionId:n}),e.lastGeneratorActivity=Date.now(),e.generatorPromise=i.startSession(e,this).catch(async c=>{let u=c?.message||"";if(["Claude executable not found","CLAUDE_CODE_PATH","ENOENT","spawn","Invalid API key","FOREIGN KEY constraint failed"].some(d=>u.includes(d))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},b.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return b.warn("SDK","SDK resume failed, falling back to standalone processing",{sessionId:e.sessionDbId,project:e.project,reason:c instanceof Error?c.message:String(c)}),this.runFallbackForTerminatedSession(e,c);throw(u.includes("aborted by user")||u.includes("No conversation found"))&&e.memorySessionId&&(b.warn("SDK","Detected stale resume failure, clearing memorySessionId for fresh start",{sessionId:e.sessionDbId,memorySessionId:e.memorySessionId,errorMessage:u}),this.dbManager.getSessionStore().updateMemorySessionId(e.sessionDbId,null),e.memorySessionId=null,e.forceInit=!0),b.error("SDK","Session generator failed",{sessionId:e.sessionDbId,project:e.project,provider:s},c),a=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},c}).finally(async()=>{let c=Ds(e.sessionDbId);if(c&&c.process.exitCode===null&&await zs(c,5e3),e.generatorPromise=null,!a&&!o&&(this.lastAiInteraction={timestamp:Date.now(),success:!0,provider:s}),o){b.warn("SYSTEM","Skipping restart due to unrecoverable error",{sessionId:e.sessionDbId}),this.broadcastProcessingStatus();return}let{PendingMessageStore:u}=(js(),Xc(Ao)),l=new u(this.dbManager.getSessionStore().db,3);if(e.idleTimedOut){b.info("SYSTEM","Generator exited due to idle timeout, not restarting",{sessionId:e.sessionDbId}),e.idleTimedOut=!1,this.broadcastProcessingStatus();return}let d=l.getPendingCount(e.sessionDbId),p=3;if(d>0){if(e.consecutiveRestarts=(e.consecutiveRestarts||0)+1,e.consecutiveRestarts>p){b.error("SYSTEM","Exceeded max pending-work restarts, stopping to prevent infinite loop",{sessionId:e.sessionDbId,pendingCount:d,consecutiveRestarts:e.consecutiveRestarts}),e.consecutiveRestarts=0,this.broadcastProcessingStatus();return}b.info("SYSTEM","Pending work remains after generator exit, restarting with fresh AbortController",{sessionId:e.sessionDbId,pendingCount:d,attempt:e.consecutiveRestarts}),e.abortController=new AbortController,this.startSessionProcessor(e,"pending-work-restart")}else e.consecutiveRestarts=0;this.broadcastProcessingStatus()})}isSessionTerminatedError(e){let n=(e instanceof Error?e.message:String(e)).toLowerCase();return n.includes("process aborted by user")||n.includes("processtransport")||n.includes("not ready for writing")||n.includes("session generator failed")||n.includes("claude code process")}async runFallbackForTerminatedSession(e,r){if(!e)return;let n=e.sessionDbId;if(!e.memorySessionId){let o=`fallback-${n}-${Date.now()}`;e.memorySessionId=o,this.dbManager.getSessionStore().updateMemorySessionId(n,o)}if(Fo())try{await this.geminiAgent.startSession(e,this);return}catch(o){b.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:o instanceof Error?o.message:String(o)})}if(Zo())try{await this.openRouterAgent.startSession(e,this);return}catch(o){b.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:o instanceof Error?o.message:String(o)})}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&b.warn("SDK","No fallback available; marked pending messages abandoned",{sessionId:n,abandoned:s}),this.sessionManager.removeSessionImmediate(n),this.sessionEventBroadcaster.broadcastSessionCompleted(n)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(js(),Ao)),n=new r(this.dbManager.getSessionStore().db,3),i=this.dbManager.getSessionStore(),s=360*60*1e3,o=Date.now()-s;try{let u=i.db.prepare(`
|
|
1596
1596
|
SELECT id FROM sdk_sessions
|
|
1597
1597
|
WHERE status = 'active' AND started_at_epoch < ?
|
|
1598
1598
|
`).all(o);if(u.length>0){let l=u.map(f=>f.id),d=l.map(()=>"?").join(",");i.db.prepare(`
|