vibelearn 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +630 -0
  2. package/README.md +287 -0
  3. package/package.json +129 -0
  4. package/plugin/.claude-plugin/CLAUDE.md +4 -0
  5. package/plugin/.claude-plugin/plugin.json +23 -0
  6. package/plugin/.cli-installed +1 -0
  7. package/plugin/CLAUDE.md +6 -0
  8. package/plugin/hooks/CLAUDE.md +6 -0
  9. package/plugin/hooks/bugfixes-2026-01-10.md +92 -0
  10. package/plugin/hooks/hooks.json +79 -0
  11. package/plugin/modes/code--ar.json +24 -0
  12. package/plugin/modes/code--bn.json +24 -0
  13. package/plugin/modes/code--chill.json +8 -0
  14. package/plugin/modes/code--cs.json +24 -0
  15. package/plugin/modes/code--da.json +24 -0
  16. package/plugin/modes/code--de.json +24 -0
  17. package/plugin/modes/code--el.json +24 -0
  18. package/plugin/modes/code--es.json +24 -0
  19. package/plugin/modes/code--fi.json +24 -0
  20. package/plugin/modes/code--fr.json +24 -0
  21. package/plugin/modes/code--he.json +24 -0
  22. package/plugin/modes/code--hi.json +24 -0
  23. package/plugin/modes/code--hu.json +24 -0
  24. package/plugin/modes/code--id.json +24 -0
  25. package/plugin/modes/code--it.json +24 -0
  26. package/plugin/modes/code--ja.json +24 -0
  27. package/plugin/modes/code--ko.json +24 -0
  28. package/plugin/modes/code--nl.json +24 -0
  29. package/plugin/modes/code--no.json +24 -0
  30. package/plugin/modes/code--pl.json +24 -0
  31. package/plugin/modes/code--pt-br.json +24 -0
  32. package/plugin/modes/code--ro.json +24 -0
  33. package/plugin/modes/code--ru.json +24 -0
  34. package/plugin/modes/code--sv.json +24 -0
  35. package/plugin/modes/code--th.json +24 -0
  36. package/plugin/modes/code--tr.json +24 -0
  37. package/plugin/modes/code--uk.json +24 -0
  38. package/plugin/modes/code--ur.json +25 -0
  39. package/plugin/modes/code--vi.json +24 -0
  40. package/plugin/modes/code--zh.json +24 -0
  41. package/plugin/modes/code.json +125 -0
  42. package/plugin/modes/email-investigation.json +120 -0
  43. package/plugin/modes/law-study--chill.json +7 -0
  44. package/plugin/modes/law-study-CLAUDE.md +85 -0
  45. package/plugin/modes/law-study.json +120 -0
  46. package/plugin/package.json +23 -0
  47. package/plugin/scripts/CLAUDE.md +5 -0
  48. package/plugin/scripts/bun-runner.js +176 -0
  49. package/plugin/scripts/mcp-server.cjs +141 -0
  50. package/plugin/scripts/smart-install.js +592 -0
  51. package/plugin/scripts/statusline-counts.js +61 -0
  52. package/plugin/scripts/vl-cli.cjs +104 -0
  53. package/plugin/scripts/worker-cli.js +19 -0
  54. package/plugin/scripts/worker-service.cjs +1919 -0
  55. package/plugin/scripts/worker-wrapper.cjs +2 -0
  56. package/plugin/skills/smart-explore/SKILL.md +145 -0
  57. package/plugin/skills/timeline-report/SKILL.md +91 -0
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env bun
2
+ "use strict";var B=Object.create;var x=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var K=Object.getPrototypeOf,X=Object.prototype.hasOwnProperty;var Z=(e,n,t,s)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of J(n))!X.call(e,r)&&r!==t&&x(e,r,{get:()=>n[r],enumerable:!(s=G(n,r))||s.enumerable});return e};var ee=(e,n,t)=>(t=e!=null?B(K(e)):{},Z(n||!e||!e.__esModule?x(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 I(e,n){let t=e+n;return t===0?0:e/t}function O(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 p=n.isCorrect?1:0,a=n.isCorrect?0:1,v=I(p,a),f=n.isCorrect?1:0,S=O(v);return e.run(`INSERT INTO vl_developer_profile
3
+ (concept_name, category, first_seen_at, last_seen_at, encounter_count,
4
+ correct_answers, incorrect_answers, current_level, streak_count, mastery_score)
5
+ VALUES (?, ?, ?, ?, 1, ?, ?, ?, ?, ?)`,[n.conceptName,n.category,t,t,p,a,S,f,v]),{concept_name:n.conceptName,category:n.category,first_seen_at:t,last_seen_at:t,encounter_count:1,correct_answers:p,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=I(r,i),l=n.isCorrect?s.streak_count+1:0,u=O(c);return e.run(`UPDATE vl_developer_profile SET
6
+ last_seen_at = ?,
7
+ encounter_count = encounter_count + 1,
8
+ correct_answers = ?,
9
+ incorrect_answers = ?,
10
+ current_level = ?,
11
+ streak_count = ?,
12
+ mastery_score = ?
13
+ WHERE concept_name = ?`,[t,r,i,u,l,c,n.conceptName]),{...s,last_seen_at:t,encounter_count:s.encounter_count+1,correct_answers:r,incorrect_answers:i,current_level:u,streak_count:l,mastery_score:c}}function k(e,n){let t=new Date().toISOString().slice(0,10);e.query("SELECT questions_answered, correct_answers FROM vl_daily_streaks WHERE date = ?").get(t)?e.run(`UPDATE vl_daily_streaks SET
14
+ questions_answered = questions_answered + 1,
15
+ correct_answers = correct_answers + ?
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 $(e){let{isCorrect:n,currentEaseFactor:t,currentIntervalDays:s,currentRepetitions:r,nowEpoch:i}=e;if(!n){let p=Math.max(1.3,t-.2);return{nextReviewAt:i+86400,easeFactor:p,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 F(e,n,t){e.run(`UPDATE vl_questions
18
+ SET next_review_at = ?,
19
+ ease_factor = ?,
20
+ interval_days = ?,
21
+ repetitions = ?
22
+ WHERE id = ?`,[t.nextReviewAt,t.easeFactor,t.intervalDays,t.repetitions,n])}function U(e,n,t,s=20){let r=t?"AND q.session_id = ?":"",i=t?[n,t,s]:[n,s];return e.query(`
23
+ SELECT q.id, q.session_id, q.question_type, q.difficulty,
24
+ q.question, q.options_json, q.correct, q.explanation, q.snippet,
25
+ q.ease_factor, q.interval_days, q.repetitions, q.follow_up_mid,
26
+ c.concept_name
27
+ FROM vl_questions q
28
+ LEFT JOIN vl_concepts c ON q.concept_id = c.id
29
+ WHERE (q.next_review_at IS NULL OR q.next_review_at <= ?)
30
+ ${r}
31
+ ORDER BY q.next_review_at ASC NULLS FIRST, q.created_at DESC
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"),L=(0,q.join)(b,"vibelearn.db"),A=(0,q.join)(b,"config.json");function H(){try{if((0,m.existsSync)(A))return JSON.parse((0,m.readFileSync)(A,"utf-8"))}catch{}return{}}function re(e){(0,m.existsSync)(b)||(0,m.mkdirSync)(b,{recursive:!0}),(0,m.writeFileSync)(A,JSON.stringify(e,null,2),"utf-8")}function h(){return(0,m.existsSync)(L)?new N.Database(L,{readonly:!0}):(console.log("No VibeLearn database found. Start a coding session first!"),null)}async function se(){let e=h();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
+ SELECT COUNT(*) as count FROM vl_questions
35
+ WHERE id NOT IN (SELECT DISTINCT question_id FROM vl_quiz_attempts)
36
+ `).get()?.count??0,i=e.query(`
37
+ SELECT category, COUNT(*) as count
38
+ FROM vl_concepts
39
+ GROUP BY category
40
+ ORDER BY count DESC
41
+ LIMIT 10
42
+ `).all(),c=e.query(`
43
+ SELECT COUNT(*) as count FROM vl_developer_profile WHERE mastery_score > 0.85
44
+ `).get()?.count??0;console.log(`
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
+ 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 ie(){let e=h();if(!e)return;let n=e.query(`
48
+ SELECT concept_name, category, mastery_score, encounter_count as times_seen
49
+ FROM vl_developer_profile
50
+ WHERE mastery_score < 0.5
51
+ ORDER BY mastery_score ASC, times_seen DESC
52
+ LIMIT 20
53
+ `).all();if(n.length===0){console.log(`
54
+ No knowledge gaps found. Keep coding and learning!
55
+ `),e.close();return}console.log(`
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 ce(e){let n=h();if(!n)return;let t=Math.floor(Date.now()/1e3),s;if(e){let o=n.query(`
58
+ SELECT session_id FROM vibelearn_session_summaries
59
+ ORDER BY generated_at DESC LIMIT 1
60
+ `).get();if(!o){console.log(`
61
+ No sessions found. Run a coding session first!
62
+ `),n.close();return}s=o.session_id}let r=U(n,t,s,20);if(n.close(),r.length===0){console.log(`
63
+ No pending questions! Great job staying on top of your learning.
64
+ `);return}let i=new N.Database(L),c=(0,j.createInterface)({input:process.stdin,output:process.stdout}),l=o=>new Promise(C=>c.question(o,C)),u=0,p=0,a=[...r],v=new Set(a.map(o=>o.id));console.log(`
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
+ `);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
+ ${C} (${o.difficulty})${W}`),o.snippet&&o.snippet.trim()&&(console.log(`
68
+ Code:
69
+ `),o.snippet.split(`
70
+ `).forEach(y=>console.log(` ${y}`)),console.log("")),console.log(` ${o.question}
71
+ `);let g="",Y=Date.now();if(o.question_type==="multiple_choice"&&o.options_json)try{JSON.parse(o.options_json).forEach((E,_)=>{let w=String.fromCharCode(65+_);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,_)=>console.log(` ${_+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 V=Date.now()-Y,D=o.question_type==="open_ended",d=!1;!D&&o.correct!==null&&(d=g.toLowerCase()===o.correct.toLowerCase()),D?console.log(`
72
+ \u270E Open-ended noted.
73
+ `):d?(console.log(`
74
+ \u2713 Correct!
75
+ `),u++):console.log(`
76
+ \u2717 Incorrect. Correct answer: ${o.correct??"(see explanation)"}
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"),p++;try{let{randomUUID:y}=await import("crypto");if(i.run(`
79
+ INSERT INTO vl_quiz_attempts (id, question_id, answer_given, is_correct, time_taken_ms, created_at)
80
+ VALUES (?, ?, ?, ?, ?, ?)
81
+ `,[y(),o.id,g,d?1:0,V,Math.floor(Date.now()/1e3)]),!o.is_follow_up){let E=$({isCorrect:d,currentEaseFactor:o.ease_factor??2.5,currentIntervalDays:o.interval_days??0,currentRepetitions:o.repetitions??0,nowEpoch:Math.floor(Date.now()/1e3)});F(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(i,{conceptName:o.concept_name,category:E?.category??"general",isCorrect:d});if(_.promoted?console.log(` \u{1F389} Level up! ${o.concept_name}: ${_.previousLevel} \u2192 ${_.profile.current_level}
82
+ `):_.demoted&&console.log(` \u{1F4C9} Level dropped: ${o.concept_name}: ${_.previousLevel} \u2192 ${_.profile.current_level}
83
+ `),Q(o,d,_.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=p>0?Math.round(u/p*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}/${p} 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 le(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
+ Logged in: API key ${r}
88
+ `)}else console.log(`
89
+ Not logged in. Run: vl login <api-key>
90
+ `);return}e||(console.error(`
91
+ Usage: vl login <api-key>
92
+ `),process.exit(1));let t=H();t.api_key=e,re(t),console.log(`
93
+ API key saved to ~/.vibelearn/config.json
94
+ `)}async function ae(){let e=process.argv.slice(2);switch(e[0]){case"quiz":await ce(e.includes("--session"));break;case"status":await se();break;case"gaps":await ie();break;case"login":{let t=e.includes("--status"),s=t?null:e[1]??null;await le(s,t);break}default:console.log(`
95
+ VibeLearn CLI \u2014 learn from your coding sessions
96
+
97
+ Usage:
98
+ vl quiz Interactive quiz (all pending questions)
99
+ vl quiz --session Quiz only the last session's questions
100
+ vl status Sessions analyzed, concepts by category
101
+ vl gaps Concepts you haven't mastered yet
102
+ vl login <api-key> Connect to vibelearn.dev
103
+ vl login --status Check login status
104
+ `)}}ae().catch(e=>{console.error("Error:",e.message),process.exit(1)});
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bun
2
+ import{existsSync as w,readFileSync as rt,writeFileSync as nt,unlinkSync as st,mkdirSync as $}from"fs";import{createWriteStream as ot}from"fs";import{join as S}from"path";import{spawn as it,spawnSync as at}from"child_process";import{homedir as ct}from"os";import{join as E,dirname as q,basename as Lt}from"path";import{homedir as z}from"os";import{fileURLToPath as Q}from"url";import{readFileSync as V,writeFileSync as j,existsSync as X}from"fs";import{join as Y}from"path";import{homedir as J}from"os";var b="bugfix,feature,refactor,discovery,decision,change",k="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var D=(s=>(s[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.SILENT=4]="SILENT",s))(D||{}),C=class{level=null;useColor;constructor(){this.useColor=process.stdout.isTTY??!1}getLevel(){if(this.level===null){let t=l.get("VIBELEARN_LOG_LEVEL").toUpperCase();this.level=D[t]??1}return this.level}correlationId(t,e){return`obs-${t}-${e}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.getLevel()===0?`${t.message}
3
+ ${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let e=Object.keys(t);return e.length===0?"{}":e.length<=3?JSON.stringify(t):`{${e.length} keys: ${e.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,e){if(!e)return t;let r=typeof e=="string"?JSON.parse(e):e;if(t==="Bash"&&r.command)return`${t}(${r.command})`;if(r.file_path)return`${t}(${r.file_path})`;if(r.notebook_path)return`${t}(${r.notebook_path})`;if(t==="Glob"&&r.pattern)return`${t}(${r.pattern})`;if(t==="Grep"&&r.pattern)return`${t}(${r.pattern})`;if(r.url)return`${t}(${r.url})`;if(r.query)return`${t}(${r.query})`;if(t==="Task"){if(r.subagent_type)return`${t}(${r.subagent_type})`;if(r.description)return`${t}(${r.description})`}return t==="Skill"&&r.skill?`${t}(${r.skill})`:t==="LSP"&&r.operation?`${t}(${r.operation})`:t}formatTimestamp(t){let e=t.getFullYear(),r=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0"),s=String(t.getHours()).padStart(2,"0"),o=String(t.getMinutes()).padStart(2,"0"),a=String(t.getSeconds()).padStart(2,"0"),c=String(t.getMilliseconds()).padStart(3,"0");return`${e}-${r}-${n} ${s}:${o}:${a}.${c}`}log(t,e,r,n,s){if(t<this.getLevel())return;let o=this.formatTimestamp(new Date),a=D[t].padEnd(5),c=e.padEnd(6),p="";n?.correlationId?p=`[${n.correlationId}] `:n?.sessionId&&(p=`[session-${n.sessionId}] `);let _="";s!=null&&(this.getLevel()===0&&typeof s=="object"?_=`
4
+ `+JSON.stringify(s,null,2):_=" "+this.formatData(s));let f="";if(n){let{sessionId:h,sdkSessionId:gt,correlationId:_t,...U}=n;Object.keys(U).length>0&&(f=` {${Object.entries(U).map(([K,B])=>`${K}=${B}`).join(", ")}}`)}let m=`[${o}] [${a}] [${c}] ${p}${r}${f}${_}`;t===3?console.error(m):console.log(m)}debug(t,e,r,n){this.log(0,t,e,r,n)}info(t,e,r,n){this.log(1,t,e,r,n)}warn(t,e,r,n){this.log(2,t,e,r,n)}error(t,e,r,n){this.log(3,t,e,r,n)}dataIn(t,e,r,n){this.info(t,`\u2192 ${e}`,r,n)}dataOut(t,e,r,n){this.info(t,`\u2190 ${e}`,r,n)}success(t,e,r,n){this.info(t,`\u2713 ${e}`,r,n)}failure(t,e,r,n){this.error(t,`\u2717 ${e}`,r,n)}timing(t,e,r,n){this.info(t,`\u23F1 ${e}`,n,{duration:`${r}ms`})}happyPathError(t,e,r,n,s=""){let p=((new Error().stack||"").split(`
5
+ `)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),_=p?`${p[1].split("/").pop()}:${p[2]}`:"unknown",f={...r,location:_};return this.warn(t,`[HAPPY-PATH] ${e}`,f,n),s}},T=new C;var l=class{static DEFAULTS={VIBELEARN_MODEL:"claude-sonnet-4-5",VIBELEARN_CONTEXT_OBSERVATIONS:"50",VIBELEARN_WORKER_PORT:"37777",VIBELEARN_WORKER_HOST:"127.0.0.1",VIBELEARN_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",VIBELEARN_PROVIDER:"claude",VIBELEARN_GEMINI_API_KEY:"",VIBELEARN_GEMINI_MODEL:"gemini-2.5-flash-lite",VIBELEARN_GEMINI_RATE_LIMITING_ENABLED:"true",VIBELEARN_OPENROUTER_API_KEY:"",VIBELEARN_OPENROUTER_MODEL:"anthropic/claude-3.5-sonnet",VIBELEARN_OPENROUTER_SITE_URL:"",VIBELEARN_OPENROUTER_APP_NAME:"vibelearn",VIBELEARN_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",VIBELEARN_OPENROUTER_MAX_TOKENS:"100000",VIBELEARN_DATA_DIR:Y(J(),".vibelearn"),VIBELEARN_LOG_LEVEL:"INFO",VIBELEARN_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",VIBELEARN_MODE:"code",VIBELEARN_CONTEXT_SHOW_READ_TOKENS:"true",VIBELEARN_CONTEXT_SHOW_WORK_TOKENS:"true",VIBELEARN_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",VIBELEARN_CONTEXT_SHOW_SAVINGS_PERCENT:"true",VIBELEARN_CONTEXT_OBSERVATION_TYPES:b,VIBELEARN_CONTEXT_OBSERVATION_CONCEPTS:k,VIBELEARN_CONTEXT_FULL_COUNT:"5",VIBELEARN_CONTEXT_FULL_FIELD:"narrative",VIBELEARN_CONTEXT_SESSION_COUNT:"10",VIBELEARN_CONTEXT_SHOW_LAST_SUMMARY:"true",VIBELEARN_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return this.DEFAULTS[t]}static getInt(t){let e=this.get(t);return parseInt(e,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){try{if(!X(t))return this.getAllDefaults();let e=V(t,"utf-8"),r=JSON.parse(e),n=r;if(r.env&&typeof r.env=="object"){n=r.env;try{j(t,JSON.stringify(n,null,2),"utf-8"),T.info("SETTINGS","Migrated settings file from nested to flat schema",{settingsPath:t})}catch(o){T.warn("SETTINGS","Failed to auto-migrate settings file",{settingsPath:t},o)}}let s={...this.DEFAULTS};for(let o of Object.keys(this.DEFAULTS))n[o]!==void 0&&(s[o]=n[o]);return s}catch(e){return T.warn("SETTINGS","Failed to load settings, using defaults",{settingsPath:t},e),this.getAllDefaults()}}};function Z(){return typeof __dirname<"u"?__dirname:q(Q(import.meta.url))}var Ut=Z(),u=l.get("VIBELEARN_DATA_DIR"),L=process.env.CLAUDE_CONFIG_DIR||E(z(),".claude"),bt=E(u,"archives"),kt=E(u,"logs"),yt=E(u,"trash"),vt=E(u,"backups"),Nt=E(u,"modes"),$t=E(u,"settings.json"),xt=E(u,"vibelearn.db"),Wt=E(u,"vector-db"),Ft=E(L,"settings.json"),Ht=E(L,"commands"),Gt=E(L,"CLAUDE.md");import{spawnSync as tt}from"child_process";import{existsSync as et}from"fs";import{join as y}from"path";import{homedir as v}from"os";function R(){let i=process.platform==="win32";try{if(tt("bun",["--version"],{encoding:"utf-8",stdio:["pipe","pipe","pipe"],shell:!1}).status===0)return"bun"}catch{}let t=i?[y(v(),".bun","bin","bun.exe")]:[y(v(),".bun","bin","bun"),"/usr/local/bin/bun","/opt/homebrew/bin/bun","/home/linuxbrew/.linuxbrew/bin/bun"];for(let e of t)if(et(e))return e;return null}function N(){return R()!==null}var d=S(u,"worker.pid"),x=S(u,"logs"),P=S(ct(),".claude","plugins","marketplaces","anergcorp"),g=class{static async start(t){if(isNaN(t)||t<1024||t>65535)return{success:!1,error:`Invalid port ${t}. Must be between 1024 and 65535`};if(await this.isRunning())return{success:!0,pid:this.getPidInfo()?.pid};$(x,{recursive:!0});let e=process.platform==="win32"?"worker-wrapper.cjs":"worker-service.cjs",r=S(P,"plugin","scripts",e);if(!w(r))return{success:!1,error:`Worker script not found at ${r}`};let n=this.getLogFilePath();return this.startWithBun(r,n,t)}static isBunAvailable(){return N()}static escapePowerShellString(t){return t.replace(/'/g,"''")}static async startWithBun(t,e,r){let n=R();if(!n)return{success:!1,error:"Bun is required but not found in PATH or common installation paths. Install from https://bun.sh"};try{if(process.platform==="win32"){let o=this.escapePowerShellString(n),a=this.escapePowerShellString(t),c=this.escapePowerShellString(P),p=this.escapePowerShellString(e),f=`${`$env:VIBELEARN_WORKER_PORT='${r}'`}; Start-Process -FilePath '${o}' -ArgumentList '${a}' -WorkingDirectory '${c}' -WindowStyle Hidden -RedirectStandardOutput '${p}' -RedirectStandardError '${p}.err' -PassThru | Select-Object -ExpandProperty Id`,m=at("powershell",["-Command",f],{stdio:"pipe",timeout:1e4,windowsHide:!0});if(m.status!==0)return{success:!1,error:`PowerShell spawn failed: ${m.stderr?.toString()||"unknown error"}`};let h=parseInt(m.stdout.toString().trim(),10);return isNaN(h)?{success:!1,error:"Failed to get PID from PowerShell"}:(this.writePidFile({pid:h,port:r,startedAt:new Date().toISOString(),version:process.env.npm_package_version||"unknown"}),this.waitForHealth(h,r))}else{let o=it(n,[t],{detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,VIBELEARN_WORKER_PORT:String(r)},cwd:P}),a=ot(e,{flags:"a"});return o.stdout?.pipe(a),o.stderr?.pipe(a),o.unref(),o.pid?(this.writePidFile({pid:o.pid,port:r,startedAt:new Date().toISOString(),version:process.env.npm_package_version||"unknown"}),this.waitForHealth(o.pid,r)):{success:!1,error:"Failed to get PID from spawned process"}}}catch(s){return{success:!1,error:s instanceof Error?s.message:String(s)}}}static async stop(t=5e3){let e=this.getPidInfo();if(process.platform==="win32"){let r=e?.port??this.getPortFromSettings();if(await this.tryHttpShutdown(r))return this.removePidFile(),!0;if(!e)return!0;let{execSync:s}=await import("child_process");try{s(`taskkill /PID ${e.pid} /T /F`,{timeout:1e4,stdio:"ignore"})}catch{}try{await this.waitForExit(e.pid,t)}catch{}return this.isProcessAlive(e.pid)||this.removePidFile(),!0}else{if(!e)return!0;try{process.kill(e.pid,"SIGTERM"),await this.waitForExit(e.pid,t)}catch{try{process.kill(e.pid,"SIGKILL")}catch{}}return this.removePidFile(),!0}}static async restart(t){return await this.stop(),this.start(t)}static async status(){let t=this.getPidInfo();if(!t)return{running:!1};let e=this.isProcessAlive(t.pid);return{running:e,pid:e?t.pid:void 0,port:e?t.port:void 0,uptime:e?this.formatUptime(t.startedAt):void 0}}static async isRunning(){let t=this.getPidInfo();if(!t)return!1;let e=this.isProcessAlive(t.pid);return e||this.removePidFile(),e}static getPortFromSettings(){try{let t=S(u,"settings.json"),e=l.loadFromFile(t);return parseInt(e.VIBELEARN_WORKER_PORT,10)}catch{return parseInt(l.get("VIBELEARN_WORKER_PORT"),10)}}static async tryHttpShutdown(t){try{return(await fetch(`http://127.0.0.1:${t}/api/admin/shutdown`,{method:"POST",signal:AbortSignal.timeout(2e3)})).ok?await this.waitForWorkerDown(t,5e3):!1}catch{return!1}}static async waitForWorkerDown(t,e){let r=Date.now();for(;Date.now()-r<e;)try{await fetch(`http://127.0.0.1:${t}/api/health`,{signal:AbortSignal.timeout(500)}),await new Promise(n=>setTimeout(n,100))}catch{return!0}return!1}static getPidInfo(){try{if(!w(d))return null;let t=rt(d,"utf-8"),e=JSON.parse(t);return typeof e.pid!="number"||typeof e.port!="number"?(logger.warn("PROCESS","Malformed PID file: missing or invalid pid/port fields",{},{parsed:e}),null):e}catch(t){return logger.warn("PROCESS","Failed to read PID file",{},{error:t instanceof Error?t.message:String(t),path:d}),null}}static writePidFile(t){$(u,{recursive:!0}),nt(d,JSON.stringify(t,null,2))}static removePidFile(){try{w(d)&&st(d)}catch{}}static isProcessAlive(t){try{return process.kill(t,0),!0}catch{return!1}}static async waitForHealth(t,e,r=1e4){let n=Date.now(),s=process.platform==="win32",o=s?r*2:r;for(;Date.now()-n<o;){if(!this.isProcessAlive(t))return{success:!1,error:s?`Process died during startup
6
+
7
+ Troubleshooting:
8
+ 1. Check Task Manager for zombie 'bun.exe' or 'node.exe' processes
9
+ 2. Verify port ${e} is not in use: netstat -ano | findstr ${e}
10
+ 3. Check worker logs in ~/.vibelearn/logs/
11
+ 4. See GitHub issues: #363, #367, #371, #373
12
+ 5. Docs: https://docs.vibelearn.dev/troubleshooting/windows-issues`:"Process died during startup"};try{if((await fetch(`http://127.0.0.1:${e}/api/readiness`,{signal:AbortSignal.timeout(1e3)})).ok)return{success:!0,pid:t}}catch{}await new Promise(c=>setTimeout(c,200))}return{success:!1,error:s?`Worker failed to start on Windows (readiness check timed out after ${o}ms)
13
+
14
+ Troubleshooting:
15
+ 1. Check Task Manager for zombie 'bun.exe' or 'node.exe' processes
16
+ 2. Verify port ${e} is not in use: netstat -ano | findstr ${e}
17
+ 3. Check worker logs in ~/.vibelearn/logs/
18
+ 4. See GitHub issues: #363, #367, #371, #373
19
+ 5. Docs: https://docs.vibelearn.dev/troubleshooting/windows-issues`:`Readiness check timed out after ${o}ms`}}static async waitForExit(t,e){let r=Date.now();for(;Date.now()-r<e;){if(!this.isProcessAlive(t))return;await new Promise(n=>setTimeout(n,100))}throw new Error("Process did not exit within timeout")}static getLogFilePath(){let t=new Date().toISOString().slice(0,10);return S(x,`worker-${t}.log`)}static formatUptime(t){let e=new Date(t).getTime(),n=Date.now()-e,s=Math.floor(n/1e3),o=Math.floor(s/60),a=Math.floor(o/60),c=Math.floor(a/24);return c>0?`${c}d ${a%24}h`:a>0?`${a}h ${o%60}m`:o>0?`${o}m ${s%60}s`:`${s}s`}};import F from"path";import{homedir as ut}from"os";var I={DEFAULT:12e4,HEALTH_CHECK:1e3,WORKER_STARTUP_WAIT:1e3,WORKER_STARTUP_RETRIES:15,PRE_RESTART_SETTLE_DELAY:2e3,WINDOWS_MULTIPLIER:1.5};function W(i){return process.platform==="win32"?Math.round(i*I.WINDOWS_MULTIPLIER):i}var ge=F.join(ut(),".claude","plugins","marketplaces","anergcorp"),_e=W(I.HEALTH_CHECK),M=null;function H(){if(M!==null)return M;let i=F.join(l.get("VIBELEARN_DATA_DIR"),"settings.json"),t=l.loadFromFile(i);return M=parseInt(t.VIBELEARN_WORKER_PORT,10),M}import{stdin as lt}from"process";var Et=process.argv[2],G=H(),O='{"continue": true, "suppressOutput": true}',A=lt.isTTY;async function pt(){switch(Et){case"start":{let i=await g.start(G);if(i.success){if(A){console.log(`Worker started (PID: ${i.pid})`);let t=new Date().toISOString().slice(0,10);console.log(`Logs: ~/.vibelearn/logs/worker-${t}.log`)}else console.log(O);process.exit(0)}else console.error(`Failed to start: ${i.error}`),process.exit(1)}case"stop":await g.stop(),console.log(A?"Worker stopped":O),process.exit(0);case"restart":{let i=await g.restart(G);i.success?(console.log(A?`Worker restarted (PID: ${i.pid})`:O),process.exit(0)):(console.error(`Failed to restart: ${i.error}`),process.exit(1))}case"status":{let i=await g.status();A?i.running?(console.log("Worker is running"),console.log(` PID: ${i.pid}`),console.log(` Port: ${i.port}`),console.log(` Uptime: ${i.uptime}`)):console.log("Worker is not running"):console.log(O),process.exit(0)}default:console.log("Usage: worker-cli.js <start|stop|restart|status>"),process.exit(1)}}pt().catch(i=>{console.error(i),process.exit(1)});