claude-mem 10.5.2 → 10.5.3
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 +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/modes/law-study--chill.json +7 -0
- package/plugin/modes/law-study-CLAUDE.md +85 -0
- package/plugin/modes/law-study.json +120 -0
- package/plugin/package.json +1 -1
- package/plugin/scripts/mcp-server.cjs +1 -1
- package/plugin/scripts/worker-service.cjs +2 -2
- package/plugin/ui/viewer-bundle.js +11 -11
- /package/plugin/{modes → hooks/modes}/code--ar.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--bn.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--chill.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--cs.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--da.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--de.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--el.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--es.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--fi.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--fr.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--he.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--hi.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--hu.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--id.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--it.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--ja.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--ko.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--nl.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--no.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--pl.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--pt-br.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--ro.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--ru.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--sv.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--th.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--tr.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--uk.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--ur.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--vi.json +0 -0
- /package/plugin/{modes → hooks/modes}/code--zh.json +0 -0
- /package/plugin/{modes → hooks/modes}/code.json +0 -0
- /package/plugin/{modes → hooks/modes}/email-investigation.json +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Law Study (Chill)",
|
|
3
|
+
"prompts": {
|
|
4
|
+
"recording_focus": "WHAT TO RECORD (HIGH SIGNAL ONLY)\n----------------------------------\nOnly record what would be painful to reconstruct later:\n- Issue-spotting triggers: specific fact patterns that signal a testable issue\n- Professor's explicit emphasis, frameworks, or exam tips\n- Counterintuitive holdings or gotchas that contradict intuition\n- Cross-case connections that reframe how a doctrine works\n- A synthesized rule only if it distills something non-obvious from multiple sources\n\nSkip anything that could be looked up in a casebook in under 60 seconds.\n\nUse verbs like: held, established, revealed, distinguished, flagged",
|
|
5
|
+
"skip_guidance": "WHEN TO SKIP (LIBERAL — WHEN IN DOUBT, SKIP)\n---------------------------------------------\nSkip freely:\n- All case briefs, even condensed ones, unless the holding is counterintuitive\n- Any rule or doctrine stated plainly in the casebook without nuance\n- Definitions of standard legal terms\n- Procedural history\n- Any fact pattern or case that wasn't specifically emphasized by the professor\n- Anything you could find again in under 60 seconds\n- **No output necessary if skipping.**"
|
|
6
|
+
}
|
|
7
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Legal Study Assistant
|
|
2
|
+
|
|
3
|
+
You are a rigorous legal study partner for a law student. Your job is to help them understand the law deeply enough to reason through novel fact patterns independently on exams and in practice.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Your Role
|
|
8
|
+
|
|
9
|
+
- Help the student read, analyze, and extract meaning from legal documents
|
|
10
|
+
- Ask questions that surface the student's reasoning, not just answers
|
|
11
|
+
- Flag what matters for exams and what professors tend to emphasize
|
|
12
|
+
- Push back when the student's analysis is imprecise or incomplete
|
|
13
|
+
- Never write their exam answers — teach them to write their own
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Reading Cases Together
|
|
18
|
+
|
|
19
|
+
When the student shares a case or document:
|
|
20
|
+
|
|
21
|
+
1. Read it fully before saying anything. No skimming.
|
|
22
|
+
2. Identify the procedural posture, then the issue, then the holding, then the reasoning.
|
|
23
|
+
3. Separate holding from dicta explicitly — this distinction is always fair game.
|
|
24
|
+
4. Surface ambiguity when the court was evasive. That ambiguity is often the exam question.
|
|
25
|
+
5. Ask: "Which facts were outcome-determinative? What if those facts changed?"
|
|
26
|
+
|
|
27
|
+
**Case briefs are always 3 sentences max:**
|
|
28
|
+
> [Key facts that triggered the issue]. The court held [holding + extracted rule]. [Why this rule exists or how it fits the doctrine — only if non-obvious.]
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Critical Questions to Drive Analysis
|
|
33
|
+
|
|
34
|
+
After reading any legal material, push the student to answer:
|
|
35
|
+
|
|
36
|
+
- What is the rule stated as elements?
|
|
37
|
+
- What did the dissent argue and why does it matter?
|
|
38
|
+
- How does this fit — or conflict with — earlier cases?
|
|
39
|
+
- What fact pattern on an exam triggers this rule?
|
|
40
|
+
- What does the professor emphasize about this? Their framing is the exam framing.
|
|
41
|
+
- Is the law settled or contested here?
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Issue Spotting
|
|
46
|
+
|
|
47
|
+
When working through a fact pattern:
|
|
48
|
+
|
|
49
|
+
1. Read the entire hypo before naming any issues.
|
|
50
|
+
2. List every potential claim and defense — err toward inclusion.
|
|
51
|
+
3. For each issue: rule → application to these specific facts → where the argument turns.
|
|
52
|
+
4. Treat "irrelevant" facts as planted triggers. Nothing in an exam hypo is accidental.
|
|
53
|
+
5. Calibrate to the professor's emphasis — they wrote the exam.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Synthesizing Doctrine
|
|
58
|
+
|
|
59
|
+
When pulling together multiple cases or a whole doctrine:
|
|
60
|
+
|
|
61
|
+
1. Find the common principle across all the cases.
|
|
62
|
+
2. Build the rule as a spectrum or taxonomy when cases represent different scenarios.
|
|
63
|
+
3. State the limiting principle — where does this rule stop and why.
|
|
64
|
+
4. Majority rule first, then minority positions with their rationale.
|
|
65
|
+
5. Identify the live tension — what the courts haven't resolved yet.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Tone and Pace
|
|
70
|
+
|
|
71
|
+
- Be direct. Law school trains precision — model it.
|
|
72
|
+
- When the student is vague, say so and ask them to be specific.
|
|
73
|
+
- Celebrate when they spot something sharp. Legal reasoning is hard.
|
|
74
|
+
- Match the student's pace — deep dive when they want to go deep, quick synthesis when they're reviewing.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Starting a Session
|
|
79
|
+
|
|
80
|
+
The student should tell you:
|
|
81
|
+
- Which course this is for
|
|
82
|
+
- What material they're working through (cases, statute, doctrine, hypo practice)
|
|
83
|
+
- What kind of help they want: deep analysis, synthesis, issue spotting, or exam review
|
|
84
|
+
|
|
85
|
+
Example: *"Contracts — working through consideration doctrine. Here are four cases. Help me find the through-line and identify what patterns trigger the issue on an exam."*
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Law Study",
|
|
3
|
+
"description": "Legal study and exam preparation for law students",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"observation_types": [
|
|
6
|
+
{
|
|
7
|
+
"id": "case-holding",
|
|
8
|
+
"label": "Case Holding",
|
|
9
|
+
"description": "Case brief (2-3 sentences: key facts + holding) with extracted legal rule",
|
|
10
|
+
"emoji": "⚖️",
|
|
11
|
+
"work_emoji": "📖"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "issue-pattern",
|
|
15
|
+
"label": "Issue Pattern",
|
|
16
|
+
"description": "Exam trigger or fact pattern that signals a legal issue to spot",
|
|
17
|
+
"emoji": "🎯",
|
|
18
|
+
"work_emoji": "🔍"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "prof-framework",
|
|
22
|
+
"label": "Prof Framework",
|
|
23
|
+
"description": "Professor's analytical lens, emphasis, or approach to a topic or doctrine",
|
|
24
|
+
"emoji": "🧑🏫",
|
|
25
|
+
"work_emoji": "📝"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "doctrine-rule",
|
|
29
|
+
"label": "Doctrine / Rule",
|
|
30
|
+
"description": "Legal test, standard, or doctrine synthesized from cases, statutes, or restatements",
|
|
31
|
+
"emoji": "📜",
|
|
32
|
+
"work_emoji": "🔍"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "argument-structure",
|
|
36
|
+
"label": "Argument Structure",
|
|
37
|
+
"description": "Legal argument or counter-argument worked through with analytical steps",
|
|
38
|
+
"emoji": "🗣️",
|
|
39
|
+
"work_emoji": "⚖️"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "cross-case-connection",
|
|
43
|
+
"label": "Cross-Case Connection",
|
|
44
|
+
"description": "Insight linking multiple cases, doctrines, or topics that reveals a deeper principle",
|
|
45
|
+
"emoji": "🔗",
|
|
46
|
+
"work_emoji": "🔍"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"observation_concepts": [
|
|
50
|
+
{
|
|
51
|
+
"id": "exam-relevant",
|
|
52
|
+
"label": "Exam Relevant",
|
|
53
|
+
"description": "Flagged by professor or likely to appear on exams based on emphasis"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "minority-position",
|
|
57
|
+
"label": "Minority Position",
|
|
58
|
+
"description": "Dissent, minority rule, or alternative jurisdictional approach worth knowing"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "gotcha",
|
|
62
|
+
"label": "Gotcha",
|
|
63
|
+
"description": "Subtle nuance, counterintuitive result, or common mistake students get wrong"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "unsettled-law",
|
|
67
|
+
"label": "Unsettled Law",
|
|
68
|
+
"description": "Circuit split, open question, or evolving area of law"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": "policy-rationale",
|
|
72
|
+
"label": "Policy Rationale",
|
|
73
|
+
"description": "Normative or policy argument underlying a rule or holding"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "course-theme",
|
|
77
|
+
"label": "Course Theme",
|
|
78
|
+
"description": "How this case or rule connects to the overarching narrative or theory of the course"
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"prompts": {
|
|
82
|
+
"system_identity": "You are Claude-Mem, a specialized observer tool for creating searchable memory FOR FUTURE SESSIONS.\n\nCRITICAL: Record what was READ, ANALYZED, SYNTHESIZED, or LEARNED about the law, not what you (the observer) are doing.\n\nYou do not have access to tools. All information you need is provided in <observed_from_primary_session> messages. Create observations from what you observe - no investigation needed.",
|
|
83
|
+
"spatial_awareness": "SPATIAL AWARENESS: Tool executions include the working directory (tool_cwd) to help you understand:\n- Which repository/project is being worked on\n- Where files are located relative to the project root\n- How to match requested paths to actual execution paths",
|
|
84
|
+
"observer_role": "Your job is to monitor a different Claude Code session happening RIGHT NOW, with the goal of creating observations and progress summaries as legal study is being done LIVE by the user. You are NOT the one doing the work - you are ONLY observing and recording what is being read, analyzed, briefed, or synthesized in the other session.",
|
|
85
|
+
"recording_focus": "WHAT TO RECORD\n--------------\nFocus on legal knowledge and exam-ready insights:\n- Case holdings distilled to 2-3 sentences (key facts + holding + rule)\n- Legal tests, elements, and standards extracted from cases or statutes\n- Issue-spotting triggers: what fact patterns signal which legal issues\n- Professor's framing, emphasis, or analytical approach to a doctrine\n- Arguments and counter-arguments worked through\n- Connections across cases or doctrines that reveal underlying principles\n\nUse verbs like: held, established, synthesized, identified, distinguished, analyzed, revealed, connected\n\n✅ GOOD EXAMPLES (describes what was learned about the law):\n- \"Palsgraf established proximate cause requires the harm be foreseeable to the defendant at the time of conduct\"\n- \"Prof frames consideration doctrine around the bargain theory, not benefit-detriment — exam answers should reflect this\"\n- \"When fact pattern shows concurrent causation, issue-spot both but-for AND substantial factor tests\"\n\n❌ BAD EXAMPLES (describes observation process - DO NOT DO THIS):\n- \"Analyzed the case and recorded findings about proximate cause\"\n- \"Tracked professor's comments and stored the framework\"\n- \"Monitored discussion of consideration and noted the approach\"",
|
|
86
|
+
"skip_guidance": "WHEN TO SKIP\n------------\nSkip these — not worth recording:\n- Full case briefs (only record the 2-3 sentence distilled version with the rule)\n- Re-reading the same case or passage without new insight\n- Definitions of basic terms the student already knows\n- Routine case brief formatting with no analytical content\n- Simple fact summaries that don't extract a rule or pattern\n- Procedural history details not relevant to the legal rule\n- **No output necessary if skipping.**",
|
|
87
|
+
"type_guidance": "**type**: MUST be EXACTLY one of these 6 options (no other values allowed):\n - case-holding: case brief (2-3 sentences: key facts + holding) with extracted legal rule\n - issue-pattern: exam trigger or fact pattern that signals a legal issue to spot\n - prof-framework: professor's analytical lens, emphasis, or approach to a topic or doctrine\n - doctrine-rule: legal test, standard, or doctrine synthesized from cases, statutes, or restatements\n - argument-structure: legal argument or counter-argument worked through with analytical steps\n - cross-case-connection: insight linking multiple cases, doctrines, or topics that reveals a deeper principle",
|
|
88
|
+
"concept_guidance": "**concepts**: 2-5 knowledge-type categories. MUST use ONLY these exact keywords:\n - exam-relevant: flagged by professor or likely to appear on exams\n - minority-position: dissent, minority rule, or alternative jurisdictional approach\n - gotcha: subtle nuance, counterintuitive result, or common mistake\n - unsettled-law: circuit split, open question, or evolving area\n - policy-rationale: normative or policy argument underlying a rule\n - course-theme: connects to the overarching narrative or theory of the course\n\n IMPORTANT: Do NOT include the observation type (case-holding/issue-pattern/etc.) as a concept.\n Types and concepts are separate dimensions.",
|
|
89
|
+
"field_guidance": "**facts**: Concise, self-contained statements\nEach fact is ONE piece of information\n No pronouns - each fact must stand alone\n Include specific details: case names, rule elements, test names, jurisdiction\n\n**files**: All files or documents read (full paths from project root)",
|
|
90
|
+
"output_format_header": "OUTPUT FORMAT\n-------------\nOutput observations using this XML structure:",
|
|
91
|
+
"format_examples": "",
|
|
92
|
+
"footer": "IMPORTANT! DO NOT do any work right now other than generating this OBSERVATIONS from tool use messages - and remember that you are a memory agent designed to summarize a DIFFERENT claude code session, not this one.\n\nNever reference yourself or your own actions. Do not output anything other than the observation content formatted in the XML structure above. All other output is ignored by the system, and the system has been designed to be smart about token usage. Please spend your tokens wisely on useful observations.\n\nRemember that we record these observations as a way of helping us stay on track with our progress, and to help us keep important decisions and changes at the forefront of our minds! :) Thank you so much for your help!",
|
|
93
|
+
|
|
94
|
+
"xml_title_placeholder": "[**title**: Case name, doctrine name, or short description of the legal insight]",
|
|
95
|
+
"xml_subtitle_placeholder": "[**subtitle**: One sentence capturing the core legal rule or exam relevance (max 24 words)]",
|
|
96
|
+
"xml_fact_placeholder": "[Concise, self-contained legal fact — include case names, rule elements, test names]",
|
|
97
|
+
"xml_narrative_placeholder": "[**narrative**: Full legal context: what the case held or rule requires, how it connects to other doctrine, why it matters for exams or practice]",
|
|
98
|
+
"xml_concept_placeholder": "[exam-relevant | minority-position | gotcha | unsettled-law | policy-rationale | course-theme]",
|
|
99
|
+
"xml_file_placeholder": "[path/to/document]",
|
|
100
|
+
|
|
101
|
+
"xml_summary_request_placeholder": "[Short title capturing the legal topic studied AND what was analyzed or synthesized]",
|
|
102
|
+
"xml_summary_investigated_placeholder": "[What cases, statutes, or doctrines were read or examined in this session?]",
|
|
103
|
+
"xml_summary_learned_placeholder": "[What legal rules, patterns, or frameworks were extracted and understood?]",
|
|
104
|
+
"xml_summary_completed_placeholder": "[What study work was completed? Which cases briefed, which doctrines synthesized, which issue patterns identified?]",
|
|
105
|
+
"xml_summary_next_steps_placeholder": "[What topics, cases, or doctrines are being studied next in this session?]",
|
|
106
|
+
"xml_summary_notes_placeholder": "[Additional insights about exam strategy, professor emphasis, or cross-topic connections observed in this session]",
|
|
107
|
+
|
|
108
|
+
"header_memory_start": "LAW STUDY MEMORY START\n=======================",
|
|
109
|
+
"header_memory_continued": "LAW STUDY MEMORY CONTINUED\n===========================",
|
|
110
|
+
"header_summary_checkpoint": "LAW STUDY SUMMARY CHECKPOINT\n============================",
|
|
111
|
+
|
|
112
|
+
"continuation_greeting": "Hello memory agent, you are continuing to observe the primary Claude session doing legal study and case analysis.",
|
|
113
|
+
"continuation_instruction": "IMPORTANT: Continue generating observations from tool use messages using the XML structure below.",
|
|
114
|
+
|
|
115
|
+
"summary_instruction": "Write progress notes of what legal material was studied, what rules and patterns were extracted, and what's next. This is a checkpoint to capture study progress so far. The session is ongoing - more cases or doctrines may be analyzed after this summary. Write \"next_steps\" as the current study trajectory (what topics or cases are actively being worked through), not as post-session plans. Always write at least a minimal summary explaining current progress, even if study is still early, so that users see a summary output tied to each study block.",
|
|
116
|
+
"summary_context_label": "Claude's Full Response to User:",
|
|
117
|
+
"summary_format_instruction": "Respond in this XML format:",
|
|
118
|
+
"summary_footer": "IMPORTANT! DO NOT do any work right now other than generating this next PROGRESS SUMMARY - and remember that you are a memory agent designed to summarize a DIFFERENT claude code session, not this one.\n\nNever reference yourself or your own actions. Do not output anything other than the summary content formatted in the XML structure above. All other output is ignored by the system, and the system has been designed to be smart about token usage. Please spend your tokens wisely on useful summary content.\n\nThank you, this summary will be very useful for keeping track of legal study progress!"
|
|
119
|
+
}
|
|
120
|
+
}
|
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 yP=new Set([".js",".jsx",".ts",".tsx",".mjs",".cjs",".py",".pyw",".go",".rs",".rb",".java",".cs",".cpp",".c",".h",".hpp",".swift",".kt",".php",".vue",".svelte"]),$P=new Set(["node_modules",".git","dist","build",".next","__pycache__",".venv","venv","env",".env","target","vendor",".cache",".turbo","coverage",".nyc_output",".claude",".smart-file-read"]),bP=512*1024;async function*p$(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!=="."||$P.has(o.name))continue;let i=(0,hi.join)(t,o.name);if(o.isDirectory())yield*p$(i,e,r-1);else if(o.isFile()){let a=o.name.slice(o.name.lastIndexOf("."));yP.has(a)&&(yield i)}}}async function xP(t){try{let e=await(0,zn.stat)(t);if(e.size>bP||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 f$(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 p$(t,t)){if(r.filePattern&&!(0,hi.relative)(t,h).toLowerCase().includes(r.filePattern.toLowerCase()))continue;let _=await xP(h);_&&a.push({absolutePath:h,relativePath:(0,hi.relative)(t,h),content:_})}let s=u$(a),c=[],u=[],l=0;for(let[h,_]of s){l+=kP(_);let E=js(h.toLowerCase(),i)>0,I=[],A=(j,Le)=>{for(let de of j){let Kt=0,Qe="",Ht=js(de.name.toLowerCase(),i);Ht>0&&(Kt+=Ht*3,Qe="name match"),de.signature.toLowerCase().includes(o)&&(Kt+=2,Qe=Qe?`${Qe} + signature`:"signature match"),de.jsdoc&&de.jsdoc.toLowerCase().includes(o)&&(Kt+=1,Qe=Qe?`${Qe} + jsdoc`:"jsdoc match"),Kt>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=js(h.symbolName.toLowerCase(),i);return js(_.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 js(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 kP(t){let e=t.symbols.length;for(let r of t.symbols)r.children&&(e+=r.children.length);return e}function m$(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 Pf=require("node:fs/promises"),Ns=require("node:path"),SP="10.5.
|
|
117
|
+
`)}var Pf=require("node:fs/promises"),Ns=require("node:path"),SP="10.5.3";console.log=(...t)=>{ve.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var wP=Yy(),zP=Qy(),vi=`http://${zP}:${wP}`,h$={search:"/api/search",timeline:"/api/timeline"};async function g$(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=`${vi}${t}?${r}`,o=await fetch(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 IP(t,e){ve.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{let r=`${vi}${t}`,n=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok){let i=await n.text();throw new Error(`Worker API error (${n.status}): ${i}`)}let o=await n.json();return ve.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(o,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 EP(){try{return(await fetch(`${vi}/api/health`)).ok}catch(t){return ve.debug("SYSTEM","Worker health check failed",{},t),!1}}var v$=[{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
|
|
@@ -920,7 +920,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
920
920
|
WHERE s.project = ?
|
|
921
921
|
`).get(r);b.info("CHROMA_SYNC","Backfilling user prompts",{project:r,missing:v.length,existing:n.prompts.size,total:y.count});let _=[];for(let x of v)_.push(this.formatUserPromptDoc(x));for(let x=0;x<_.length;x+=this.BATCH_SIZE){let S=_.slice(x,x+this.BATCH_SIZE);await this.addDocuments(S),b.debug("CHROMA_SYNC","Backfill progress",{project:r,progress:`${Math.min(x+this.BATCH_SIZE,_.length)}/${_.length}`})}b.info("CHROMA_SYNC","Smart backfill complete",{project:r,synced:{observationDocs:u.length,summaryDocs:f.length,promptDocs:_.length},skipped:{observations:n.observations.size,summaries:n.summaries.size,prompts:n.prompts.size}})}catch(o){throw b.error("CHROMA_SYNC","Backfill failed",{project:r},o),new Error(`Backfill failed: ${o instanceof Error?o.message:String(o)}`)}finally{i.close()}}async queryChroma(e,r,n){await this.ensureCollectionExists();try{let o=await Gi.getInstance().callTool("chroma_query_documents",{collection_name:this.collectionName,query_texts:[e],n_results:r,...n&&{where:n},include:["documents","metadatas","distances"]}),s=[],a=new Set,c=o?.ids?.[0]||[],u=o?.metadatas?.[0]||[],l=o?.distances?.[0]||[],d=[],p=[];for(let m=0;m<c.length;m++){let f=c[m],g=f.match(/obs_(\d+)_/),h=f.match(/summary_(\d+)_/),v=f.match(/prompt_(\d+)/),y=null;g?y=parseInt(g[1],10):h?y=parseInt(h[1],10):v&&(y=parseInt(v[1],10)),y!==null&&!a.has(y)&&(a.add(y),s.push(y),d.push(u[m]??null),p.push(l[m]??0))}return{ids:s,distances:p,metadatas:d}}catch(i){let o=i instanceof Error?i.message:String(i);throw o.includes("ECONNREFUSED")||o.includes("ENOTFOUND")||o.includes("fetch failed")||o.includes("subprocess closed")||o.includes("timed out")?(this.collectionCreated=!1,b.error("CHROMA_SYNC","Connection lost during query",{project:this.project,query:e},i),new Error(`Chroma query failed - connection lost: ${o}`)):(b.error("CHROMA_SYNC","Query failed",{project:this.project,query:e},i),i)}}static async backfillAllProjects(){let e=new Wi,r=new t("claude-mem");try{let n=e.db.prepare("SELECT DISTINCT project FROM observations WHERE project IS NOT NULL AND project != ?").all("");b.info("CHROMA_SYNC",`Backfill check for ${n.length} projects`);for(let{project:i}of n)try{await r.ensureBackfilled(i)}catch(o){b.error("CHROMA_SYNC",`Backfill failed for project: ${i}`,{},o)}}finally{await r.close(),e.close()}}async close(){b.info("CHROMA_SYNC","ChromaSync closed",{project:this.project})}};var Af=require("fs"),k0=require("path"),tA=require("os"),Z7="claude-mem@thedotmack";function Nf(){try{let t=process.env.CLAUDE_CONFIG_DIR||(0,k0.join)((0,tA.homedir)(),".claude"),e=(0,k0.join)(t,"settings.json");if(!(0,Af.existsSync)(e))return!1;let r=(0,Af.readFileSync)(e,"utf-8");return JSON.parse(r)?.enabledPlugins?.[Z7]===!1}catch{return!1}}var hi=Ye(require("path"),1),T0=require("os"),Dt=require("fs"),Ki=require("child_process"),iA=require("util");de();Tn();var Mf=(0,iA.promisify)(Ki.exec),I0=hi.default.join((0,T0.homedir)(),".claude-mem"),gi=hi.default.join(I0,"worker.pid");var rA=30;function nA(t){return t?/(^|[\\/])bun(\.exe)?$/i.test(t.trim()):!1}function H7(t,e){let r=e==="win32"?`where ${t}`:`which ${t}`;try{return(0,Ki.execSync)(r,{stdio:["ignore","pipe","ignore"],encoding:"utf-8",windowsHide:!0}).split(/\r?\n/).map(o=>o.trim()).find(o=>o.length>0)||null}catch{return null}}function B7(t={}){let e=t.platform??process.platform,r=t.execPath??process.execPath;if(e!=="win32"||nA(r))return r;let n=t.env??process.env,i=t.homeDirectory??(0,T0.homedir)(),o=t.pathExists??Dt.existsSync,s=t.lookupInPath??H7,a=[n.BUN,n.BUN_PATH,hi.default.join(i,".bun","bin","bun.exe"),hi.default.join(i,".bun","bin","bun"),n.USERPROFILE?hi.default.join(n.USERPROFILE,".bun","bin","bun.exe"):void 0,n.LOCALAPPDATA?hi.default.join(n.LOCALAPPDATA,"bun","bun.exe"):void 0,n.LOCALAPPDATA?hi.default.join(n.LOCALAPPDATA,"bun","bin","bun.exe"):void 0];for(let c of a){let u=c?.trim();if(u&&(nA(u)&&o(u)||u.toLowerCase()==="bun"))return u}return s("bun",e)}function oA(t){(0,Dt.mkdirSync)(I0,{recursive:!0}),(0,Dt.writeFileSync)(gi,JSON.stringify(t,null,2))}function Df(){if(!(0,Dt.existsSync)(gi))return null;try{return JSON.parse((0,Dt.readFileSync)(gi,"utf-8"))}catch(t){return b.warn("SYSTEM","Failed to parse PID file",{path:gi},t),null}}function Wn(){if((0,Dt.existsSync)(gi))try{(0,Dt.unlinkSync)(gi)}catch(t){b.warn("SYSTEM","Failed to remove PID file",{path:gi},t)}}function Io(t){return process.platform==="win32"?Math.round(t*2):t}async function sA(t){if(process.platform!=="win32")return[];if(!Number.isInteger(t)||t<=0)return b.warn("SYSTEM","Invalid parent PID for child process enumeration",{parentPid:t}),[];try{let e=`powershell -NoProfile -NonInteractive -Command "Get-CimInstance Win32_Process -Filter 'ParentProcessId=${t}' | Select-Object -ExpandProperty ProcessId"`,{stdout:r}=await Mf(e,{timeout:$r.POWERSHELL_COMMAND,windowsHide:!0});return r.split(`
|
|
922
922
|
`).map(n=>n.trim()).filter(n=>n.length>0&&/^\d+$/.test(n)).map(n=>parseInt(n,10)).filter(n=>n>0)}catch(e){return b.error("SYSTEM","Failed to enumerate child processes",{parentPid:t},e),[]}}async function aA(t){if(!Number.isInteger(t)||t<=0){b.warn("SYSTEM","Invalid PID for force kill",{pid:t});return}try{process.platform==="win32"?await Mf(`taskkill /PID ${t} /T /F`,{timeout:$r.POWERSHELL_COMMAND,windowsHide:!0}):process.kill(t,"SIGKILL"),b.info("SYSTEM","Killed process",{pid:t})}catch(e){b.debug("SYSTEM","Process already exited during force kill",{pid:t},e)}}async function cA(t,e){let r=Date.now();for(;Date.now()-r<e;){let n=t.filter(i=>{try{return process.kill(i,0),!0}catch{return!1}});if(n.length===0){b.info("SYSTEM","All child processes exited");return}b.debug("SYSTEM","Waiting for processes to exit",{stillAlive:n}),await new Promise(i=>setTimeout(i,100))}b.warn("SYSTEM","Timeout waiting for child processes to exit")}function V7(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 o=e.match(/^(\d+):(\d+)$/);return o?parseInt(o[1],10):-1}var $0=["worker-service.cjs","chroma-mcp"],G7=["mcp-server.cjs"];async function uA(){let t=process.platform==="win32",e=process.pid,r=[],n=[...$0,...G7];try{if(t){let o=`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:s}=await Mf(o,{timeout:$r.POWERSHELL_COMMAND,windowsHide:!0});if(!s.trim()||s.trim()==="null"){b.debug("SYSTEM","No orphaned claude-mem processes found (Windows)");return}let a=JSON.parse(s),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($0.some(f=>p.includes(f)))r.push(d),b.debug("SYSTEM","Found orphaned process (aggressive)",{pid:d,commandLine:p.substring(0,80)});else{let f=l.CreationDate?.match(/\/Date\((\d+)\)\//);if(f){let g=parseInt(f[1],10),h=(u-g)/(1e3*60);h>=rA&&(r.push(d),b.debug("SYSTEM","Found orphaned process (age-gated)",{pid:d,ageMinutes:Math.round(h)}))}}}}else{let i=n.join("|"),{stdout:o}=await Mf(`ps -eo pid,etime,command | grep -E "${i}" | grep -v grep || true`);if(!o.trim()){b.debug("SYSTEM","No orphaned claude-mem processes found (Unix)");return}let s=o.trim().split(`
|
|
923
|
-
`);for(let a of s){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($0.some(m=>d.includes(m)))r.push(u),b.debug("SYSTEM","Found orphaned process (aggressive)",{pid:u,command:d.substring(0,80)});else{let m=V7(l);m>=rA&&(r.push(u),b.debug("SYSTEM","Found orphaned process (age-gated)",{pid:u,ageMinutes:m,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,Ki.execSync)(`taskkill /PID ${i} /T /F`,{timeout:$r.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(o){b.debug("SYSTEM","Failed to kill process, may have already exited",{pid:i},o)}}else for(let i of r)try{process.kill(i,"SIGKILL")}catch(o){b.debug("SYSTEM","Process already exited",{pid:i},o)}b.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var W7=".chroma-cleaned-v10.3";function lA(t){let e=t??I0,r=hi.default.join(e,W7),n=hi.default.join(e,"chroma");if((0,Dt.existsSync)(r)){b.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}b.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,Dt.existsSync)(n)&&((0,Dt.rmSync)(n,{recursive:!0,force:!0}),b.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,Dt.mkdirSync)(e,{recursive:!0}),(0,Dt.writeFileSync)(r,new Date().toISOString()),b.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function O0(t,e,r={}){let n=process.platform==="win32",i={...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r};if(n){let a=B7();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,Ki.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 o="/usr/bin/setsid";if((0,Dt.existsSync)(o)){let a=(0,Ki.spawn)(o,[process.execPath,t,"--daemon"],{detached:!0,stdio:"ignore",env:i});return a.pid===void 0?void 0:(a.unref(),a.pid)}let s=(0,Ki.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(s.pid!==void 0)return s.unref(),s.pid}function R0(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 dA(t=15e3){try{let e=(0,Dt.statSync)(gi);return Date.now()-e.mtimeMs<t}catch{return!1}}function pA(){try{if(!(0,Dt.existsSync)(gi))return;let t=new Date;(0,Dt.utimesSync)(gi,t,t)}catch{}}function mA(){let t=Df();t&&(R0(t.pid)||(b.info("SYSTEM","Removing stale PID file (worker process is dead)",{pid:t.pid,port:t.port,startedAt:t.startedAt}),Wn()))}function fA(t,e){return async r=>{if(e.value){b.warn("SYSTEM",`Received ${r} but shutdown already in progress`);return}e.value=!0,b.info("SYSTEM",`Received ${r}, shutting down...`);try{await t(),process.exit(0)}catch(n){b.error("SYSTEM","Error during shutdown",{},n),process.exit(0)}}}var hA=Ye(require("path"),1),gA=require("fs");de();Mt();async function Ha(t){try{return(await fetch(`http://127.0.0.1:${t}/api/health`)).ok}catch{return!1}}async function vA(t,e,r,n){let i=Date.now();for(;Date.now()-i<r;){try{if((await fetch(`http://127.0.0.1:${t}${e}`)).ok)return!0}catch(o){b.debug("SYSTEM",n,{port:t},o)}await new Promise(o=>setTimeout(o,500))}return!1}function Ba(t,e=3e4){return vA(t,"/api/health",e,"Service not ready yet, will retry")}function yA(t,e=3e4){return vA(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function jf(t,e=1e4){let r=Date.now();for(;Date.now()-r<e;){if(!await Ha(t))return!0;await new Promise(n=>setTimeout(n,500))}return!1}async function zf(t){try{let e=await fetch(`http://127.0.0.1:${t}/api/admin/shutdown`,{method:"POST"});return e.ok?!0:(b.warn("SYSTEM","Shutdown request returned error",{port:t,status:e.status}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(b.debug("SYSTEM","Worker already stopped",{port:t},e),!1):(b.error("SYSTEM","Shutdown request failed unexpectedly",{port:t},e),!1)}}function K7(){try{let t=hA.default.join(Vi,"package.json");return JSON.parse((0,gA.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 J7(t){try{let e=await fetch(`http://127.0.0.1:${t}/api/version`);return e.ok?(await e.json()).version:null}catch{return b.debug("SYSTEM","Could not fetch worker version",{port:t}),null}}async function _A(t){let e=K7(),r=await J7(t);return!r||e==="unknown"?{matches:!0,pluginVersion:e,workerVersion:r}:{matches:e===r,pluginVersion:e,workerVersion:r}}de();async function bA(t){b.info("SYSTEM","Shutdown initiated"),Wn();let e=await sA(process.pid);if(b.info("SYSTEM","Found child processes",{count:e.length,pids:e}),t.server&&(await X7(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(),e.length>0){b.info("SYSTEM","Force killing remaining children");for(let r of e)await aA(r);await cA(e,5e3)}b.info("SYSTEM","Worker shutdown complete")}async function X7(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 R2=Ye(Bh(),1),DE=Ye(require("fs"),1),kd=Ye(require("path"),1);var v2=["search","context","summarize","import","export"],y2=["workflow","search_params","examples","all"];de();var AE=Ye(Bh(),1),E2=Ye(w2(),1),k2=Ye(require("path"),1);Mt();de();function NE(t){let e=[];e.push(AE.default.json({limit:"50mb"})),e.push((0,E2.default)({origin:(i,o)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?o(null,!0):o(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,o,s)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(f=>i.path.endsWith(f)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return s();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);b.info("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let m=o.send.bind(o);o.send=function(f){let g=Date.now()-l;return b.info("HTTP",`\u2190 ${o.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),m(f)},s()});let r=Xr(),n=k2.default.join(r,"plugin","ui");return e.push(AE.default.static(n)),e}function Vh(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 ME(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":""}de();var _c=class extends Error{constructor(r,n=500,i,o){super(r);this.statusCode=n;this.code=i;this.details=o;this.name="AppError"}};function $2(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var T2=(t,e,r,n)=>{let i=t instanceof _c?t.statusCode:500;b.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof _c?t.code:void 0},t);let o=$2(t.name||"Error",t.message,t instanceof _c?t.code:void 0,t instanceof _c?t.details:void 0);r.status(i).json(o)};function I2(t,e){e.status(404).json($2("NotFound",`Cannot ${t.method} ${t.path}`))}var O2="10.5.2",Gh=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,R2.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(I2),this.app.use(T2)}setupMiddleware(){NE(ME).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:O2,workerPath:this.options.workerPath,uptime:Date.now()-this.startTime,managed:process.env.CLAUDE_MEM_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:O2})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!y2.includes(n))return r.status(400).json({error:"Invalid topic"});try{let o;if(i){if(!v2.includes(i))return r.status(400).json({error:"Invalid operation"});let s=kd.default.resolve(__dirname,"../skills/mem-search/operations"),a=kd.default.resolve(s,`${i}.md`);if(!a.startsWith(s+kd.default.sep))return r.status(400).json({error:"Invalid request"});o=await DE.promises.readFile(a,"utf-8")}else{let s=kd.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await DE.promises.readFile(s,"utf-8");o=this.extractInstructionSection(a,n)}r.json({content:[{type:"text",text:o}]})}catch{r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",Vh,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_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",Vh,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_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)})}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),o=e.indexOf(n);return i===-1?e:o===-1?e.substring(i):e.substring(i,o).trim()}};var vt=Ye(require("path"),1),Td=require("os"),Gt=require("fs"),A2=require("child_process"),N2=require("util");de();Ur();Mt();var Cn=require("fs"),$d=require("path");de();function P2(t){try{return(0,Cn.existsSync)(t)?JSON.parse((0,Cn.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 C2(t,e){let r=(0,$d.join)(t,"..");(0,Cn.mkdirSync)(r,{recursive:!0}),(0,Cn.writeFileSync)(t,JSON.stringify(e,null,2))}function jE(t,e){let r=(0,$d.join)(t,".cursor","rules"),n=(0,$d.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,Cn.mkdirSync)(r,{recursive:!0});let o=`---
|
|
923
|
+
`);for(let a of s){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($0.some(m=>d.includes(m)))r.push(u),b.debug("SYSTEM","Found orphaned process (aggressive)",{pid:u,command:d.substring(0,80)});else{let m=V7(l);m>=rA&&(r.push(u),b.debug("SYSTEM","Found orphaned process (age-gated)",{pid:u,ageMinutes:m,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,Ki.execSync)(`taskkill /PID ${i} /T /F`,{timeout:$r.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(o){b.debug("SYSTEM","Failed to kill process, may have already exited",{pid:i},o)}}else for(let i of r)try{process.kill(i,"SIGKILL")}catch(o){b.debug("SYSTEM","Process already exited",{pid:i},o)}b.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var W7=".chroma-cleaned-v10.3";function lA(t){let e=t??I0,r=hi.default.join(e,W7),n=hi.default.join(e,"chroma");if((0,Dt.existsSync)(r)){b.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}b.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,Dt.existsSync)(n)&&((0,Dt.rmSync)(n,{recursive:!0,force:!0}),b.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,Dt.mkdirSync)(e,{recursive:!0}),(0,Dt.writeFileSync)(r,new Date().toISOString()),b.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function O0(t,e,r={}){let n=process.platform==="win32",i={...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r};if(n){let a=B7();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,Ki.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 o="/usr/bin/setsid";if((0,Dt.existsSync)(o)){let a=(0,Ki.spawn)(o,[process.execPath,t,"--daemon"],{detached:!0,stdio:"ignore",env:i});return a.pid===void 0?void 0:(a.unref(),a.pid)}let s=(0,Ki.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(s.pid!==void 0)return s.unref(),s.pid}function R0(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 dA(t=15e3){try{let e=(0,Dt.statSync)(gi);return Date.now()-e.mtimeMs<t}catch{return!1}}function pA(){try{if(!(0,Dt.existsSync)(gi))return;let t=new Date;(0,Dt.utimesSync)(gi,t,t)}catch{}}function mA(){let t=Df();t&&(R0(t.pid)||(b.info("SYSTEM","Removing stale PID file (worker process is dead)",{pid:t.pid,port:t.port,startedAt:t.startedAt}),Wn()))}function fA(t,e){return async r=>{if(e.value){b.warn("SYSTEM",`Received ${r} but shutdown already in progress`);return}e.value=!0,b.info("SYSTEM",`Received ${r}, shutting down...`);try{await t(),process.exit(0)}catch(n){b.error("SYSTEM","Error during shutdown",{},n),process.exit(0)}}}var hA=Ye(require("path"),1),gA=require("fs");de();Mt();async function Ha(t){try{return(await fetch(`http://127.0.0.1:${t}/api/health`)).ok}catch{return!1}}async function vA(t,e,r,n){let i=Date.now();for(;Date.now()-i<r;){try{if((await fetch(`http://127.0.0.1:${t}${e}`)).ok)return!0}catch(o){b.debug("SYSTEM",n,{port:t},o)}await new Promise(o=>setTimeout(o,500))}return!1}function Ba(t,e=3e4){return vA(t,"/api/health",e,"Service not ready yet, will retry")}function yA(t,e=3e4){return vA(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function jf(t,e=1e4){let r=Date.now();for(;Date.now()-r<e;){if(!await Ha(t))return!0;await new Promise(n=>setTimeout(n,500))}return!1}async function zf(t){try{let e=await fetch(`http://127.0.0.1:${t}/api/admin/shutdown`,{method:"POST"});return e.ok?!0:(b.warn("SYSTEM","Shutdown request returned error",{port:t,status:e.status}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(b.debug("SYSTEM","Worker already stopped",{port:t},e),!1):(b.error("SYSTEM","Shutdown request failed unexpectedly",{port:t},e),!1)}}function K7(){try{let t=hA.default.join(Vi,"package.json");return JSON.parse((0,gA.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 J7(t){try{let e=await fetch(`http://127.0.0.1:${t}/api/version`);return e.ok?(await e.json()).version:null}catch{return b.debug("SYSTEM","Could not fetch worker version",{port:t}),null}}async function _A(t){let e=K7(),r=await J7(t);return!r||e==="unknown"?{matches:!0,pluginVersion:e,workerVersion:r}:{matches:e===r,pluginVersion:e,workerVersion:r}}de();async function bA(t){b.info("SYSTEM","Shutdown initiated"),Wn();let e=await sA(process.pid);if(b.info("SYSTEM","Found child processes",{count:e.length,pids:e}),t.server&&(await X7(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(),e.length>0){b.info("SYSTEM","Force killing remaining children");for(let r of e)await aA(r);await cA(e,5e3)}b.info("SYSTEM","Worker shutdown complete")}async function X7(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 R2=Ye(Bh(),1),DE=Ye(require("fs"),1),kd=Ye(require("path"),1);var v2=["search","context","summarize","import","export"],y2=["workflow","search_params","examples","all"];de();var AE=Ye(Bh(),1),E2=Ye(w2(),1),k2=Ye(require("path"),1);Mt();de();function NE(t){let e=[];e.push(AE.default.json({limit:"50mb"})),e.push((0,E2.default)({origin:(i,o)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?o(null,!0):o(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,o,s)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(f=>i.path.endsWith(f)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return s();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);b.info("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let m=o.send.bind(o);o.send=function(f){let g=Date.now()-l;return b.info("HTTP",`\u2190 ${o.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),m(f)},s()});let r=Xr(),n=k2.default.join(r,"plugin","ui");return e.push(AE.default.static(n)),e}function Vh(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 ME(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":""}de();var _c=class extends Error{constructor(r,n=500,i,o){super(r);this.statusCode=n;this.code=i;this.details=o;this.name="AppError"}};function $2(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var T2=(t,e,r,n)=>{let i=t instanceof _c?t.statusCode:500;b.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof _c?t.code:void 0},t);let o=$2(t.name||"Error",t.message,t instanceof _c?t.code:void 0,t instanceof _c?t.details:void 0);r.status(i).json(o)};function I2(t,e){e.status(404).json($2("NotFound",`Cannot ${t.method} ${t.path}`))}var O2="10.5.3",Gh=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,R2.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(I2),this.app.use(T2)}setupMiddleware(){NE(ME).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:O2,workerPath:this.options.workerPath,uptime:Date.now()-this.startTime,managed:process.env.CLAUDE_MEM_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:O2})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!y2.includes(n))return r.status(400).json({error:"Invalid topic"});try{let o;if(i){if(!v2.includes(i))return r.status(400).json({error:"Invalid operation"});let s=kd.default.resolve(__dirname,"../skills/mem-search/operations"),a=kd.default.resolve(s,`${i}.md`);if(!a.startsWith(s+kd.default.sep))return r.status(400).json({error:"Invalid request"});o=await DE.promises.readFile(a,"utf-8")}else{let s=kd.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await DE.promises.readFile(s,"utf-8");o=this.extractInstructionSection(a,n)}r.json({content:[{type:"text",text:o}]})}catch{r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",Vh,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_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",Vh,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_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)})}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),o=e.indexOf(n);return i===-1?e:o===-1?e.substring(i):e.substring(i,o).trim()}};var vt=Ye(require("path"),1),Td=require("os"),Gt=require("fs"),A2=require("child_process"),N2=require("util");de();Ur();Mt();var Cn=require("fs"),$d=require("path");de();function P2(t){try{return(0,Cn.existsSync)(t)?JSON.parse((0,Cn.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 C2(t,e){let r=(0,$d.join)(t,"..");(0,Cn.mkdirSync)(r,{recursive:!0}),(0,Cn.writeFileSync)(t,JSON.stringify(e,null,2))}function jE(t,e){let r=(0,$d.join)(t,".cursor","rules"),n=(0,$d.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,Cn.mkdirSync)(r,{recursive:!0});let o=`---
|
|
924
924
|
alwaysApply: true
|
|
925
925
|
description: "Claude-mem context from past sessions (auto-updated)"
|
|
926
926
|
---
|
|
@@ -1425,7 +1425,7 @@ Tips:
|
|
|
1425
1425
|
`&&u++;if(u>=e||f===0)break;a=Math.min(a*2,i,s)}let l=c.split(`
|
|
1426
1426
|
`);l.length>0&&l[l.length-1]===""&&l.pop();let d=Math.max(0,l.length-e),p=l.slice(d),m;if(i<=a)m=l.length;else{let f=c.length/Math.max(u,1);m=Math.round(i/f)}return{lines:p.join(`
|
|
1427
1427
|
`),totalEstimate:m}}finally{(0,gn.closeSync)(r)}}var sv=class extends Pr{getLogFilePath(){let e=_e.get("CLAUDE_MEM_DATA_DIR"),r=(0,ov.join)(e,"logs"),n=new Date().toISOString().split("T")[0];return(0,ov.join)(r,`claude-mem-${n}.log`)}getLogsDir(){let e=_e.get("CLAUDE_MEM_DATA_DIR");return(0,ov.join)(e,"logs")}setupRoutes(e){e.get("/api/logs",this.handleGetLogs.bind(this)),e.post("/api/logs/clear",this.handleClearLogs.bind(this))}handleGetLogs=this.wrapHandler((e,r)=>{let n=this.getLogFilePath();if(!(0,gn.existsSync)(n)){r.json({logs:"",path:n,exists:!1});return}let i=parseInt(e.query.lines||"1000",10),o=Math.min(i,1e4),{lines:s,totalEstimate:a}=fhe(n,o),c=s===""?0:s.split(`
|
|
1428
|
-
`).length;r.json({logs:s,path:n,exists:!0,totalLines:a,returnedLines:c})});handleClearLogs=this.wrapHandler((e,r)=>{let n=this.getLogFilePath();if(!(0,gn.existsSync)(n)){r.json({success:!0,message:"Log file does not exist",path:n});return}(0,gn.writeFileSync)(n,"","utf-8"),b.info("SYSTEM","Log file cleared via UI",{path:n}),r.json({success:!0,message:"Log file cleared",path:n})})};de();var av=class extends Pr{constructor(r,n){super();this.dbManager=r;this.defaultProject=n}setupRoutes(r){r.post("/api/memory/save",this.handleSaveMemory.bind(this))}handleSaveMemory=this.wrapHandler(async(r,n)=>{let{text:i,title:o,project:s}=r.body,a=s||this.defaultProject;if(!i||typeof i!="string"||i.trim().length===0){this.badRequest(n,"text is required and must be non-empty");return}let c=this.dbManager.getSessionStore(),u=this.dbManager.getChromaSync(),l=c.getOrCreateManualSession(a),d={type:"discovery",title:o||i.substring(0,60).trim()+(i.length>60?"...":""),subtitle:"Manual memory",facts:[],narrative:i,concepts:[],files_read:[],files_modified:[]},p=c.storeObservation(l,a,d,0,0);b.info("HTTP","Manual observation saved",{id:p.id,project:a,title:d.title}),u.syncObservation(p.id,l,a,d,0,p.createdAtEpoch,0).catch(m=>{b.error("CHROMA","ChromaDB sync failed",{id:p.id},m)}),n.json({success:!0,id:p.id,title:d.title,project:a,message:`Memory saved as observation #${p.id}`})})};var Zhe={},Mhe=120*1e3;function x$(){return b$.default.join(_e.get("CLAUDE_MEM_DATA_DIR"),".worker-start-attempted")}function Dhe(){if(process.platform!=="win32")return!1;let t=x$();if(!(0,co.existsSync)(t))return!1;try{let e=(0,co.statSync)(t).mtimeMs;return Date.now()-e<Mhe}catch{return!1}}function jhe(){if(process.platform==="win32")try{(0,co.writeFileSync)(x$(),"","utf-8")}catch{}}function zhe(){if(process.platform==="win32")try{let t=x$();(0,co.existsSync)(t)&&(0,co.unlinkSync)(t)}catch{}}var Uhe="10.5.2";function l9(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var gp=class{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;searchRoutes=null;chromaMcpManager=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 Yh(this.dbManager),this.sseBroadcaster=new Qh,this.sdkAgent=new Pg(this.dbManager,this.sessionManager),this.geminiAgent=new Cg(this.dbManager,this.sessionManager),this.openRouterAgent=new Mg(this.dbManager,this.sessionManager),this.paginationHelper=new Dg(this.dbManager),this.settingsManager=new jg(this.dbManager),this.sessionEventBroadcaster=new qg(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new ja({name:"worker-search-proxy",version:Uhe},{capabilities:{}}),this.server=new Gh({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return Kc()&&qs()?e="openrouter":Wc()&&Ls()&&(e="gemini"),{provider:e,authMethod:Pf(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){let e={value:this.isShuttingDown},r=fA(()=>this.shutdown(),e);process.on("SIGTERM",()=>{this.isShuttingDown=e.value,r("SIGTERM")}),process.on("SIGINT",()=>{this.isShuttingDown=e.value,r("SIGINT")}),process.platform!=="win32"&&(process.argv.includes("--daemon")?process.on("SIGHUP",()=>{b.debug("SYSTEM","Ignoring SIGHUP in daemon mode")}):process.on("SIGHUP",()=>{this.isShuttingDown=e.value,r("SIGHUP")}))}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,o=new Promise((s,a)=>setTimeout(()=>a(new Error("Database initialization timeout")),i));try{await Promise.race([this.initializationComplete,o]),n()}catch(s){b.error("HTTP",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized`,{},s),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 iv(this.settingsManager)),this.server.registerRoutes(new sv),this.server.registerRoutes(new av(this.dbManager,"claude-mem"))}async start(){let e=ht(),r=Rf();await this.server.listen(e,r),oA({pid:process.pid,port:e,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 uA();let{ModeManager:e}=await Promise.resolve().then(()=>(Fr(),W2)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(Xt(),CC)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(Mt(),FC)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&lA(),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Gi.getInstance(),b.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):b.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let s=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(s),b.info("SYSTEM",`Mode loaded: ${s}`),await this.dbManager.initialize();let{PendingMessageStore:a}=await Promise.resolve().then(()=>(jo(),Ps)),u=new a(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);u>0&&b.info("SYSTEM",`Reset ${u} stale processing messages to pending`);let l=new Ug,d=new Lg,p=new zg(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),l,d);this.searchRoutes=new tv(p),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)"),this.chromaMcpManager&&Za.backfillAllProjects().then(()=>{b.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(y=>{b.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},y)});let m=b$.default.join(__dirname,"mcp-server.cjs"),f=new La({command:"node",args:[m],env:process.env}),g=3e5,h=this.mcpClient.connect(f),v=new Promise((y,_)=>setTimeout(()=>_(new Error("MCP connection timeout after 5 minutes")),g));await Promise.race([h,v]),this.mcpReady=!0,b.success("WORKER","MCP server connected"),this.stopOrphanReaper=V2(()=>{let y=new Set;for(let[_]of this.sessionManager.sessions)y.add(_);return y}),b.info("SYSTEM","Started orphan reaper (runs every 5 minutes)"),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 Kc()&&qs()?this.openRouterAgent:Wc()&&Ls()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let n=e.sessionDbId,i=this.getActiveAgent(),o=i.constructor.name;e.abortController.signal.aborted&&(b.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let s=!1,a=!1;b.info("SYSTEM",`Starting generator (${r}) using ${o}`,{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"].some(d=>u.includes(d))){s=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:o,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:o},c),a=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:o,error:u},c}).finally(async()=>{let c=zo(e.sessionDbId);if(c&&!c.process.killed&&c.process.exitCode===null&&await Uo(c,5e3),e.generatorPromise=null,!a&&!s&&(this.lastAiInteraction={timestamp:Date.now(),success:!0,provider:o}),s){b.warn("SYSTEM","Skipping restart due to unrecoverable error",{sessionId:e.sessionDbId}),this.broadcastProcessingStatus();return}let{PendingMessageStore:u}=(jo(),tu(Ps)),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);d>0&&(b.info("SYSTEM","Pending work remains after generator exit, restarting with fresh AbortController",{sessionId:e.sessionDbId,pendingCount:d}),e.abortController=new AbortController,this.startSessionProcessor(e,"pending-work-restart")),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 s=`fallback-${n}-${Date.now()}`;e.memorySessionId=s,this.dbManager.getSessionStore().updateMemorySessionId(n,s)}if(Ls())try{await this.geminiAgent.startSession(e,this);return}catch(s){b.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:s instanceof Error?s.message:String(s)})}if(qs())try{await this.openRouterAgent.startSession(e,this);return}catch(s){b.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:s instanceof Error?s.message:String(s)})}let o=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);o>0&&b.warn("SDK","No fallback available; marked pending messages abandoned",{sessionId:n,abandoned:o}),this.sessionManager.removeSessionImmediate(n),this.sessionEventBroadcaster.broadcastSessionCompleted(n)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(jo(),Ps)),n=new r(this.dbManager.getSessionStore().db,3),i=this.dbManager.getSessionStore(),o=360*60*1e3,s=Date.now()-o;try{let u=i.db.prepare(`
|
|
1428
|
+
`).length;r.json({logs:s,path:n,exists:!0,totalLines:a,returnedLines:c})});handleClearLogs=this.wrapHandler((e,r)=>{let n=this.getLogFilePath();if(!(0,gn.existsSync)(n)){r.json({success:!0,message:"Log file does not exist",path:n});return}(0,gn.writeFileSync)(n,"","utf-8"),b.info("SYSTEM","Log file cleared via UI",{path:n}),r.json({success:!0,message:"Log file cleared",path:n})})};de();var av=class extends Pr{constructor(r,n){super();this.dbManager=r;this.defaultProject=n}setupRoutes(r){r.post("/api/memory/save",this.handleSaveMemory.bind(this))}handleSaveMemory=this.wrapHandler(async(r,n)=>{let{text:i,title:o,project:s}=r.body,a=s||this.defaultProject;if(!i||typeof i!="string"||i.trim().length===0){this.badRequest(n,"text is required and must be non-empty");return}let c=this.dbManager.getSessionStore(),u=this.dbManager.getChromaSync(),l=c.getOrCreateManualSession(a),d={type:"discovery",title:o||i.substring(0,60).trim()+(i.length>60?"...":""),subtitle:"Manual memory",facts:[],narrative:i,concepts:[],files_read:[],files_modified:[]},p=c.storeObservation(l,a,d,0,0);b.info("HTTP","Manual observation saved",{id:p.id,project:a,title:d.title}),u.syncObservation(p.id,l,a,d,0,p.createdAtEpoch,0).catch(m=>{b.error("CHROMA","ChromaDB sync failed",{id:p.id},m)}),n.json({success:!0,id:p.id,title:d.title,project:a,message:`Memory saved as observation #${p.id}`})})};var Zhe={},Mhe=120*1e3;function x$(){return b$.default.join(_e.get("CLAUDE_MEM_DATA_DIR"),".worker-start-attempted")}function Dhe(){if(process.platform!=="win32")return!1;let t=x$();if(!(0,co.existsSync)(t))return!1;try{let e=(0,co.statSync)(t).mtimeMs;return Date.now()-e<Mhe}catch{return!1}}function jhe(){if(process.platform==="win32")try{(0,co.writeFileSync)(x$(),"","utf-8")}catch{}}function zhe(){if(process.platform==="win32")try{let t=x$();(0,co.existsSync)(t)&&(0,co.unlinkSync)(t)}catch{}}var Uhe="10.5.3";function l9(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var gp=class{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;searchRoutes=null;chromaMcpManager=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 Yh(this.dbManager),this.sseBroadcaster=new Qh,this.sdkAgent=new Pg(this.dbManager,this.sessionManager),this.geminiAgent=new Cg(this.dbManager,this.sessionManager),this.openRouterAgent=new Mg(this.dbManager,this.sessionManager),this.paginationHelper=new Dg(this.dbManager),this.settingsManager=new jg(this.dbManager),this.sessionEventBroadcaster=new qg(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new ja({name:"worker-search-proxy",version:Uhe},{capabilities:{}}),this.server=new Gh({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return Kc()&&qs()?e="openrouter":Wc()&&Ls()&&(e="gemini"),{provider:e,authMethod:Pf(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){let e={value:this.isShuttingDown},r=fA(()=>this.shutdown(),e);process.on("SIGTERM",()=>{this.isShuttingDown=e.value,r("SIGTERM")}),process.on("SIGINT",()=>{this.isShuttingDown=e.value,r("SIGINT")}),process.platform!=="win32"&&(process.argv.includes("--daemon")?process.on("SIGHUP",()=>{b.debug("SYSTEM","Ignoring SIGHUP in daemon mode")}):process.on("SIGHUP",()=>{this.isShuttingDown=e.value,r("SIGHUP")}))}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,o=new Promise((s,a)=>setTimeout(()=>a(new Error("Database initialization timeout")),i));try{await Promise.race([this.initializationComplete,o]),n()}catch(s){b.error("HTTP",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized`,{},s),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 iv(this.settingsManager)),this.server.registerRoutes(new sv),this.server.registerRoutes(new av(this.dbManager,"claude-mem"))}async start(){let e=ht(),r=Rf();await this.server.listen(e,r),oA({pid:process.pid,port:e,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 uA();let{ModeManager:e}=await Promise.resolve().then(()=>(Fr(),W2)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(Xt(),CC)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(Mt(),FC)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&lA(),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Gi.getInstance(),b.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):b.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let s=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(s),b.info("SYSTEM",`Mode loaded: ${s}`),await this.dbManager.initialize();let{PendingMessageStore:a}=await Promise.resolve().then(()=>(jo(),Ps)),u=new a(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);u>0&&b.info("SYSTEM",`Reset ${u} stale processing messages to pending`);let l=new Ug,d=new Lg,p=new zg(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),l,d);this.searchRoutes=new tv(p),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)"),this.chromaMcpManager&&Za.backfillAllProjects().then(()=>{b.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(y=>{b.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},y)});let m=b$.default.join(__dirname,"mcp-server.cjs"),f=new La({command:"node",args:[m],env:process.env}),g=3e5,h=this.mcpClient.connect(f),v=new Promise((y,_)=>setTimeout(()=>_(new Error("MCP connection timeout after 5 minutes")),g));await Promise.race([h,v]),this.mcpReady=!0,b.success("WORKER","MCP server connected"),this.stopOrphanReaper=V2(()=>{let y=new Set;for(let[_]of this.sessionManager.sessions)y.add(_);return y}),b.info("SYSTEM","Started orphan reaper (runs every 5 minutes)"),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 Kc()&&qs()?this.openRouterAgent:Wc()&&Ls()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let n=e.sessionDbId,i=this.getActiveAgent(),o=i.constructor.name;e.abortController.signal.aborted&&(b.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let s=!1,a=!1;b.info("SYSTEM",`Starting generator (${r}) using ${o}`,{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"].some(d=>u.includes(d))){s=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:o,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:o},c),a=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:o,error:u},c}).finally(async()=>{let c=zo(e.sessionDbId);if(c&&!c.process.killed&&c.process.exitCode===null&&await Uo(c,5e3),e.generatorPromise=null,!a&&!s&&(this.lastAiInteraction={timestamp:Date.now(),success:!0,provider:o}),s){b.warn("SYSTEM","Skipping restart due to unrecoverable error",{sessionId:e.sessionDbId}),this.broadcastProcessingStatus();return}let{PendingMessageStore:u}=(jo(),tu(Ps)),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);d>0&&(b.info("SYSTEM","Pending work remains after generator exit, restarting with fresh AbortController",{sessionId:e.sessionDbId,pendingCount:d}),e.abortController=new AbortController,this.startSessionProcessor(e,"pending-work-restart")),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 s=`fallback-${n}-${Date.now()}`;e.memorySessionId=s,this.dbManager.getSessionStore().updateMemorySessionId(n,s)}if(Ls())try{await this.geminiAgent.startSession(e,this);return}catch(s){b.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:s instanceof Error?s.message:String(s)})}if(qs())try{await this.openRouterAgent.startSession(e,this);return}catch(s){b.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:s instanceof Error?s.message:String(s)})}let o=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);o>0&&b.warn("SDK","No fallback available; marked pending messages abandoned",{sessionId:n,abandoned:o}),this.sessionManager.removeSessionImmediate(n),this.sessionEventBroadcaster.broadcastSessionCompleted(n)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(jo(),Ps)),n=new r(this.dbManager.getSessionStore().db,3),i=this.dbManager.getSessionStore(),o=360*60*1e3,s=Date.now()-o;try{let u=i.db.prepare(`
|
|
1429
1429
|
SELECT id FROM sdk_sessions
|
|
1430
1430
|
WHERE status = 'active' AND started_at_epoch < ?
|
|
1431
1431
|
`).all(s);if(u.length>0){let l=u.map(m=>m.id),d=l.map(()=>"?").join(",");i.db.prepare(`
|