@chatpanel/events 0.290.0 → 0.329.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/agent-card-view.js +1 -1
  2. package/agent-permission.js +2 -2
  3. package/agent-session-open.js +1 -0
  4. package/agent-thread.js +5 -0
  5. package/attached-paths.js +1 -1
  6. package/browser-relay.js +1 -1
  7. package/client-prefs.js +1 -1
  8. package/clock.js +1 -0
  9. package/compaction.js +4 -4
  10. package/context-select.js +2 -0
  11. package/context-window.js +1 -1
  12. package/dialect-a2a.js +1 -1
  13. package/dialect-claude.js +1 -1
  14. package/digest.js +7 -0
  15. package/entitlement.js +1 -1
  16. package/fetched.js +2 -2
  17. package/find-tool.js +1 -1
  18. package/harness-cards.js +1 -1
  19. package/history-search.js +6 -6
  20. package/identity.js +1 -0
  21. package/index.js +1 -1
  22. package/kokoro-text.js +1 -1
  23. package/link-connect.js +1 -1
  24. package/link-protocol.js +1 -1
  25. package/link-routes.js +2 -0
  26. package/link-sync.js +5 -0
  27. package/memory.js +2 -2
  28. package/model-candidates.js +1 -1
  29. package/note-merge.js +9 -9
  30. package/note-tool.js +2 -2
  31. package/own-instructions.js +5 -0
  32. package/package.json +25 -1
  33. package/prefetch.js +4 -2
  34. package/provider-presets.js +1 -1
  35. package/research.js +7 -7
  36. package/retrieval-plan.js +1 -0
  37. package/sandbox-policy.js +1 -1
  38. package/search-modes.js +6 -6
  39. package/service-standby.js +1 -0
  40. package/settings-registry.js +1 -1
  41. package/stitch.js +16 -14
  42. package/thread-send.js +1 -0
  43. package/tool-group-data.js +1 -1
  44. package/tool-hints.js +4 -4
  45. package/tool-hub.js +4 -4
  46. package/tool-need.js +3 -3
  47. package/tool-result.js +2 -2
  48. package/turn-loop.js +4 -4
  49. package/vault.js +1 -1
  50. package/voice-intents.js +2 -2
  51. package/voice-sample.js +1 -1
  52. package/weather-tool.js +10 -1
  53. package/weather.js +2 -2
package/research.js CHANGED
@@ -1,16 +1,16 @@
1
- import{lexicalPlan as te}from"./recall.js";import{namesIn as ne}from"./search-modes.js";import{recall as se}from"./memory.js";import{splitForWindow as oe,partChars as O,partPrompt as ie,mapParts as re,reduceNotes as ae}from"./stitch.js";import{normalizeCorrections as le}from"./search-modes.js";import{defineSchema as U,describeSchema as z,parseStructured as B}from"./structured.js";const R=Object.freeze({rounds:2,records:3,chunks:10,chunkChars:2800,parts:16,ms:6e4}),q=[["meeting",/\b(meetings?|calls?|standups?|syncs?|1:1s?|one[- ]on[- ]ones?)\b/i],["note",/\bnotes?\b/i],["chat",/\b(chats?|conversations?)\b/i]],G=/\b(last|latest|most recent|recent|newest)\b/i,H=/\b(first|earliest|oldest)\b/i,ce=/\b(how many|how often|number of|count)\b/i,de=/\b(list|which|all (?:my|the)|every)\b/i,W=/\b(summari[sz]e|summary|what (?:was|is) it about|what was (?:discussed|said)|details?|in detail|tell me more|go deeper|deeper|explain|what did (?:we|they|he|she|i) (?:say|discuss|decide|talk about))\b/i,K=/^(?:meet|meets|met|meeting|talk|talked|speak|spoke|chat|chatted|most|often|frequent|frequently|common|top|people|attendees?|participants?|contacts?|shows?|attends?|joins?|busiest|months?|weeks?|days?|monthly|weekly|daily|per|each|every|count|many|much)$/i,Q=/\b(?:who (?:do|did|have) i (?:meet|met|talk(?:ed)?|speak|spoke|chat(?:ted)?)(?: with| to)?(?: the)? most(?: often)?|most (?:frequent|common|met) (?:people|attendees|participants|contacts)|top (?:people|attendees|participants|contacts)|who (?:shows up|attends|joins) (?:the )?most)\b/i,J=/\b(?:per|by|each|every|a) (month|week|day)\b|\b(monthly|weekly|daily)\b|\bwhich (month|week|day)\b|\bbusiest (month|week|day)\b/i,he=/\b(who (?:else )?(?:was|were) (?:in|at|on|there)|who (?:joined|attended|spoke|was there)|attendees?|participants?|who (?:else )?(?:is|are) in)\b/i,ue=/\b(even later|later than that|more recent|after that|newer)\b/i,me=/\b(even earlier|earlier than that|before that|older)\b/i,pe=/^\s*(?:no\b|nope\b|not that\b|it\b|that\b|this\b|and\b|also\b|what about\b|how about\b|what was it\b|summari[sz]e\b|more\b|even\b)/i,fe=/\b(\d{4}-\d{2}-\d{2}|(?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]*\.? \d{1,2}(?:st|nd|rd|th)?,? \d{4}|\d{1,2}(?:st|nd|rd|th)? (?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]* \d{4})\b/i;function we(n){const s=fe.exec(String(n||""));if(!s)return 0;const h=Date.parse(s[1].replace(/(\d)(st|nd|rd|th)/i,"$1").replace(/\bsept\b/i,"sep"));return Number.isFinite(h)?h:0}function ge(n,{previous:s=null,knownNames:h=[],now:a=Date.now()}={}){const i=String(n||""),c=i.toLowerCase(),o=te(i,{now:a}),p=h.filter(m=>m&&new RegExp(`\\b${String(m).toLowerCase().replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\b`).test(c)),k=[...new Set([...ne(i),...p])],u=q.find(([,m])=>m.test(i))?.[0]||"",E=new Set(k.flatMap(m=>m.toLowerCase().split(/\s+/))),e={intent:Q.test(i)||J.test(i)?"group":he.test(i)?"people":ce.test(i)?"count":G.test(i)?"latest":H.test(i)?"earliest":de.test(i)?"list":W.test(i)?"detail":"find",kind:u,names:k,terms:o.terms.filter(m=>!E.has(m)&&!q.some(([,v])=>v.test(m))&&!G.test(m)&&!H.test(m)),sort:"relevance",limit:8,since:o.sinceAt||0,after:0,before:0,readFull:W.test(i),followUp:!1,target:null,group:""};if(e.intent==="group"){const m=J.exec(i),v=m?(m[1]||m[2]||m[3]||m[4]||"").toLowerCase().replace(/ly$/,"").replace(/^dai$/,"day"):"";e.group=Q.test(i)?"person":v,e.group==="person"&&(e.kind=e.kind||"meeting"),e.terms=e.terms.filter($=>!K.test($)),e.limit=5}e.intent==="latest"&&(e.sort="newest",e.limit=5),e.intent==="earliest"&&(e.sort="oldest",e.limit=5),e.intent==="list"&&(e.limit=12),e.intent==="people"&&(e.sort="newest",e.limit=3,e.readFull=!0,e.kind=e.kind||"meeting");const w=s?.plan;if(w&&(pe.test(i)||/\b(?:the|that|this) (?:meeting|call|chat|note)\b/i.test(i)||!k.length&&!u&&i.trim().split(/\s+/).length<=6)){e.followUp=!0,e.kind=e.kind||w.kind,e.names=e.names.length?e.names:w.names,e.terms=e.terms.length?e.terms:w.terms;const m=we(s.answer);ue.test(i)?(e.intent="latest",e.sort="newest",e.after=m?m+864e5:w.after,e.limit=5):me.test(i)?(e.intent="earliest",e.sort="newest",e.before=m||w.before,e.limit=5):e.intent==="people"?e.target=s.top||null:e.readFull||/\b(it|that|this)\b/i.test(i)?(e.intent="detail",e.readFull=!0,e.target=s.top||null,e.sort=w.sort):(e.intent=w.intent,e.sort=w.sort)}return(e.intent==="latest"||e.intent==="earliest")&&(e.readFull=e.readFull||!1),e}function be(n,s,h){if(n.length<=h)return n;const a=[...s.names||[],...s.terms||[]].map(c=>String(c).toLowerCase()).filter(c=>c.length>2),i=n.filter(c=>a.some(o=>c.text.toLowerCase().includes(o)));return[...i,...n.filter(c=>!i.includes(c))].slice(0,h).sort((c,o)=>c.at-o.at)}function ye(n,s,{chunkChars:h=R.chunkChars,max:a=R.chunks}={}){const i=String(n||""),c=[];for(let u=0;u<i.length;u+=h)c.push({at:u,text:i.slice(u,u+h)});const o=[...s.names||[],...s.terms||[]].map(u=>String(u).toLowerCase()).filter(u=>u.length>2);if(!o.length||c.length<=a)return c.slice(0,a);const p=c.filter(u=>o.some(E=>u.text.toLowerCase().includes(E))),k=c.filter(u=>!p.includes(u));return[...p,...k].slice(0,a).sort((u,E)=>u.at-E.at)}const L=n=>n?new Date(n).toISOString().slice(0,10):"",ke=new RegExp("^\\s*(?:\\[\\s*\\d{1,2}:\\d{2}(?::\\d{2})?(?:\\s*[AaPp]\\.?[Mm]\\.?)?\\s*\\]\\s*|\\(?\\d{1,2}:\\d{2}(?::\\d{2})?(?:\\s*[AaPp]\\.?[Mm]\\.?)?\\)?\\s+)?(?:\\*\\*)?(\\p{Lu}[\\p{L}\\p{N}'. -]{0,48}?(?:\\s*[([][^()[\\]\\n]{1,40}[)\\]])?)(?:\\*\\*)?\\s*(?:_?\\(\\d{1,2}:\\d{2}(?::\\d{2})?\\)_?)?\\s*:\\s+\\S","gmu"),$e=/^(https?|note|notes|summary|topics|action items|key moments|decisions?|risks?|questions?|meeting|transcript|date|time|duration|title|subject|agenda|location|attendees|participants|speakers?|recording|source|link|url|tags?|status|owner|next steps)$/i;function Se(n){const s=new Map;for(const h of String(n||"").matchAll(ke)){const a=h[1].replace(/\s*[([]\d{1,2}:\d{2}(?::\d{2})?[)\]]$/,"").trim(),i=a.replace(/\s*[([][^()[\]]*[)\]]$/,"").trim();if(!i||$e.test(i))continue;const c=i.toLowerCase(),o=s.get(c);o?o.lines++:s.set(c,{name:a,lines:1})}return[...s.values()].sort((h,a)=>a.lines-h.lines)}function xe(n,s=""){if(!Array.isArray(n))return null;const h=o=>String(o||"").replace(/\s*[([][^()[\]]*[)\]]$/,"").trim().toLowerCase(),a=String(s||"").trim().toLowerCase(),i=o=>!!a&&(o===a||!a.includes(" ")&&o.split(/\s+/)[0]===a),c=new Map;for(const o of n){const p=h(o?.key);if(!p||i(p))continue;const k=c.get(p);k?k.count+=Number(o.count)||0:c.set(p,{key:String(o.key).trim(),count:Number(o.count)||0})}return[...c.values()].sort((o,p)=>p.count-o.count||o.key.localeCompare(p.key))}const V=U({name:"frame",purpose:"what kind of question about the person's own records this is",fields:{intent:{type:"enum",values:["find","latest","earliest","count","group","people","list","detail"],required:!0,describe:"latest/earliest: the most recent or first one; count: how many; group: counts per person or per month/week/day; people: who was there; list: several items; detail: what one said or was about; find: anything else"},kind:{type:"enum",values:["","meeting","note","chat"],describe:"the kind of record asked about, or empty"},names:{type:"string[]",max:3,describe:"people named in the question, exactly as written; empty when none"},group:{type:"enum",values:["","person","month","week","day"],describe:"for group: what to count by; else empty"}}});function Ce(n){return`Classify this question about the person's own chats, notes and meetings.
1
+ import{lexicalPlan as oe}from"./recall.js";import{namesIn as re}from"./search-modes.js";import{recall as ie}from"./memory.js";import{splitForWindow as ae,partChars as q,partPrompt as le,mapParts as ce,reduceNotes as de}from"./stitch.js";import{normalizeCorrections as he}from"./search-modes.js";import{defineSchema as z,describeSchema as B,parseStructured as G}from"./structured.js";import{withoutOwnInstructions as H}from"./own-instructions.js";import{isSmallWindow as ue}from"./context-window.js";const F=Object.freeze({rounds:2,records:3,chunks:10,chunkChars:2800,parts:16,ms:6e4}),W=[["meeting",/\b(meetings?|calls?|standups?|syncs?|1:1s?|one[- ]on[- ]ones?)\b/i],["note",/\bnotes?\b/i],["chat",/\b(chats?|conversations?)\b/i]],K=/\b(last|latest|most recent|recent|newest)\b/i,Q=/\b(first|earliest|oldest)\b/i,me=/\b(how many|how often|number of|count)\b/i,pe=/\b(list|which|all (?:my|the)|every)\b/i,J=/\b(summari[sz]e|summary|what (?:was|is) it about|what was (?:discussed|said)|details?|in detail|tell me more|go deeper|deeper|explain|what did (?:we|they|he|she|i) (?:say|discuss|decide|talk about))\b/i,V=/^(?:meet|meets|met|meeting|talk|talked|speak|spoke|chat|chatted|most|often|frequent|frequently|common|top|people|attendees?|participants?|contacts?|shows?|attends?|joins?|busiest|months?|weeks?|days?|monthly|weekly|daily|per|each|every|count|many|much)$/i,Y=/\b(?:who (?:do|did|have) i (?:meet|met|talk(?:ed)?|speak|spoke|chat(?:ted)?)(?: with| to)?(?: the)? most(?: often)?|most (?:frequent|common|met) (?:people|attendees|participants|contacts)|top (?:people|attendees|participants|contacts)|who (?:shows up|attends|joins) (?:the )?most)\b/i,X=/\b(?:per|by|each|every|a) (month|week|day)\b|\b(monthly|weekly|daily)\b|\bwhich (month|week|day)\b|\bbusiest (month|week|day)\b/i,fe=/\b(who (?:else )?(?:was|were) (?:in|at|on|there)|who (?:joined|attended|spoke|was there)|attendees?|participants?|who (?:else )?(?:is|are) in)\b/i,we=/\b(even later|later than that|more recent|after that|newer)\b/i,ge=/\b(even earlier|earlier than that|before that|older)\b/i,be=/^\s*(?:no\b|nope\b|not that\b|it\b|that\b|this\b|and\b|also\b|what about\b|how about\b|what was it\b|summari[sz]e\b|more\b|even\b)/i,ye=/\b(\d{4}-\d{2}-\d{2}|(?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]*\.? \d{1,2}(?:st|nd|rd|th)?,? \d{4}|\d{1,2}(?:st|nd|rd|th)? (?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]* \d{4})\b/i;function ke(n){const s=ye.exec(String(n||""));if(!s)return 0;const d=Date.parse(s[1].replace(/(\d)(st|nd|rd|th)/i,"$1").replace(/\bsept\b/i,"sep"));return Number.isFinite(d)?d:0}function $e(n,{previous:s=null,knownNames:d=[],now:a=Date.now()}={}){const r=String(n||""),c=r.toLowerCase(),o=oe(r,{now:a}),p=d.filter(m=>m&&new RegExp(`\\b${String(m).toLowerCase().replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\b`).test(c)),k=[...new Set([...re(r),...p])],u=W.find(([,m])=>m.test(r))?.[0]||"",x=new Set(k.flatMap(m=>m.toLowerCase().split(/\s+/))),e={intent:Y.test(r)||X.test(r)?"group":fe.test(r)?"people":me.test(r)?"count":K.test(r)?"latest":Q.test(r)?"earliest":pe.test(r)?"list":J.test(r)?"detail":"find",kind:u,names:k,terms:o.terms.filter(m=>!x.has(m)&&!W.some(([,L])=>L.test(m))&&!K.test(m)&&!Q.test(m)),sort:"relevance",limit:8,since:o.sinceAt||0,after:0,before:0,readFull:J.test(r),followUp:!1,target:null,group:""};if(e.intent==="group"){const m=X.exec(r),L=m?(m[1]||m[2]||m[3]||m[4]||"").toLowerCase().replace(/ly$/,"").replace(/^dai$/,"day"):"";e.group=Y.test(r)?"person":L,e.group==="person"&&(e.kind=e.kind||"meeting"),e.terms=e.terms.filter($=>!V.test($)),e.limit=5}e.intent==="latest"&&(e.sort="newest",e.limit=5),e.intent==="earliest"&&(e.sort="oldest",e.limit=5),e.intent==="list"&&(e.limit=12),e.intent==="people"&&(e.sort="newest",e.limit=3,e.readFull=!0,e.kind=e.kind||"meeting");const b=s?.plan;if(b&&(be.test(r)||/\b(?:the|that|this) (?:meeting|call|chat|note)\b/i.test(r)||!k.length&&!u&&r.trim().split(/\s+/).length<=6)){e.followUp=!0,e.kind=e.kind||b.kind,e.names=e.names.length?e.names:b.names,e.terms=e.terms.length?e.terms:b.terms;const m=ke(s.answer);we.test(r)?(e.intent="latest",e.sort="newest",e.after=m?m+864e5:b.after,e.limit=5):ge.test(r)?(e.intent="earliest",e.sort="newest",e.before=m||b.before,e.limit=5):e.intent==="people"?e.target=s.top||null:e.readFull||/\b(it|that|this)\b/i.test(r)?(e.intent="detail",e.readFull=!0,e.target=s.top||null,e.sort=b.sort):(e.intent=b.intent,e.sort=b.sort)}return(e.intent==="latest"||e.intent==="earliest")&&(e.readFull=e.readFull||!1),e}function Se(n,s,d){if(n.length<=d)return n;const a=[...s.names||[],...s.terms||[]].map(c=>String(c).toLowerCase()).filter(c=>c.length>2),r=n.filter(c=>a.some(o=>c.text.toLowerCase().includes(o)));return[...r,...n.filter(c=>!r.includes(c))].slice(0,d).sort((c,o)=>c.at-o.at)}function xe(n,s,{chunkChars:d=F.chunkChars,max:a=F.chunks}={}){const r=String(n||""),c=[];for(let u=0;u<r.length;u+=d)c.push({at:u,text:r.slice(u,u+d)});const o=[...s.names||[],...s.terms||[]].map(u=>String(u).toLowerCase()).filter(u=>u.length>2);if(!o.length||c.length<=a)return c.slice(0,a);const p=c.filter(u=>o.some(x=>u.text.toLowerCase().includes(x))),k=c.filter(u=>!p.includes(u));return[...p,...k].slice(0,a).sort((u,x)=>u.at-x.at)}const E=n=>n?new Date(n).toISOString().slice(0,10):"",Ce=new RegExp("^\\s*(?:\\[\\s*\\d{1,2}:\\d{2}(?::\\d{2})?(?:\\s*[AaPp]\\.?[Mm]\\.?)?\\s*\\]\\s*|\\(?\\d{1,2}:\\d{2}(?::\\d{2})?(?:\\s*[AaPp]\\.?[Mm]\\.?)?\\)?\\s+)?(?:\\*\\*)?(\\p{Lu}[\\p{L}\\p{N}'. -]{0,48}?(?:\\s*[([][^()[\\]\\n]{1,40}[)\\]])?)(?:\\*\\*)?\\s*(?:_?\\(\\d{1,2}:\\d{2}(?::\\d{2})?\\)_?)?\\s*:\\s+\\S","gmu"),Ae=/^(https?|note|notes|summary|topics|action items|key moments|decisions?|risks?|questions?|meeting|transcript|date|time|duration|title|subject|agenda|location|attendees|participants|speakers?|recording|source|link|url|tags?|status|owner|next steps)$/i;function Ee(n){const s=new Map;for(const d of String(n||"").matchAll(Ce)){const a=d[1].replace(/\s*[([]\d{1,2}:\d{2}(?::\d{2})?[)\]]$/,"").trim(),r=a.replace(/\s*[([][^()[\]]*[)\]]$/,"").trim();if(!r||Ae.test(r))continue;const c=r.toLowerCase(),o=s.get(c);o?o.lines++:s.set(c,{name:a,lines:1})}return[...s.values()].sort((d,a)=>a.lines-d.lines)}function Le(n,s=""){if(!Array.isArray(n))return null;const d=o=>String(o||"").replace(/\s*[([][^()[\]]*[)\]]$/,"").trim().toLowerCase(),a=String(s||"").trim().toLowerCase(),r=o=>!!a&&(o===a||!a.includes(" ")&&o.split(/\s+/)[0]===a),c=new Map;for(const o of n){const p=d(o?.key);if(!p||r(p))continue;const k=c.get(p);k?k.count+=Number(o.count)||0:c.set(p,{key:String(o.key).trim(),count:Number(o.count)||0})}return[...c.values()].sort((o,p)=>p.count-o.count||o.key.localeCompare(p.key))}const Z=z({name:"frame",purpose:"what kind of question about the person's own records this is",fields:{intent:{type:"enum",values:["find","latest","earliest","count","group","people","list","detail"],required:!0,describe:"latest/earliest: the most recent or first one; count: how many; group: counts per person or per month/week/day; people: who was there; list: several items; detail: what one said or was about; find: anything else"},kind:{type:"enum",values:["","meeting","note","chat"],describe:"the kind of record asked about, or empty"},names:{type:"string[]",max:3,describe:"people named in the question, exactly as written; empty when none"},group:{type:"enum",values:["","person","month","week","day"],describe:"for group: what to count by; else empty"}}});function ve(n){return`Classify this question about the person's own chats, notes and meetings.
2
2
 
3
- ${z(V)}
3
+ ${B(Z)}
4
4
 
5
- Question: ${String(n).slice(0,400)}`}const Y=U({name:"evidence",purpose:"whether what was found answers the question",fields:{answered:{type:"enum",values:["yes","partly","no"],required:!0,describe:"yes when the found text answers the question, partly when it answers some of it, no when it does not"},missing:{type:"string",max:120,describe:"when not yes: a few search words (names, topics, dates) for what is missing; else empty"}}});function Ee(n,s,{maxChars:h=6e3}={}){const a=String(s||"");return`Does the text found below answer the question? Judge only from the text.
5
+ Question: ${String(n).slice(0,400)}`}const ee=z({name:"evidence",purpose:"whether what was found answers the question",fields:{answered:{type:"enum",values:["yes","partly","no"],required:!0,describe:"yes when the found text answers the question, partly when it answers some of it, no when it does not"},missing:{type:"string",max:120,describe:"when not yes: a few search words (names, topics, dates) for what is missing; else empty"}}});function Te(n,s,{maxChars:d=6e3}={}){const a=String(s||"");return`Does the text found below answer the question? Judge only from the text.
6
6
 
7
- ${z(Y)}
7
+ ${B(ee)}
8
8
 
9
9
  Question: ${String(n).slice(0,400)}
10
10
 
11
11
  ---
12
- ${a.length>h?`${a.slice(0,h)}
13
- …`:a}`}function Ae(n){const s={meeting:"meetings",note:"notes",chat:"chats"}[n.kind]||"records",h=n.names.length?` naming ${n.names.join(" and ")}`:"",a=n.terms.length?` about ${n.terms.slice(0,6).join(", ")}`:"",i=[n.after?`after ${L(n.after-864e5)}`:"",n.before?`before ${L(n.before)}`:"",n.since?`since ${L(n.since)}`:""].filter(Boolean).join(", "),c=n.sort==="newest"?", newest first":n.sort==="oldest"?", oldest first":", most relevant first";return`${s}${h}${a}${i?` ${i}`:""}${c}`}async function Pe(n,{query:s,readText:h,searchModes:a=null,complete:i=null,memories:c=[],previous:o=null,knownNames:p=[],limits:k=R,now:u=()=>Date.now(),mapWindow:E=0,answerWindow:e=0,parallel:w=1,corrections:m=null,self:v=""}={}){const $=u(),y={...R,...k},_=le(m),F=new Set(_.notNames),T=new Set(_.hidden),t=ge(n,{previous:o,knownNames:p.filter(l=>!F.has(String(l).toLowerCase())),now:$}),X=String(n||""),I={framedBy:"rules"};if(t.names=t.names.filter(l=>!F.has(String(l).toLowerCase())),t.target&&T.has(t.target)&&(t.target=null),i&&y.modelFrame!==!1&&t.intent==="find"&&!t.followUp&&!t.target){const l=await i(Ce(n),{maxTokens:90}).catch(()=>""),d=B(l,V);if(d){I.framedBy="model",d.intent&&d.intent!=="find"&&(t.intent=d.intent),!t.kind&&d.kind&&(t.kind=d.kind);const f=(d.names||[]).map(g=>String(g).trim()).filter(g=>g&&X.toLowerCase().includes(g.toLowerCase())&&!F.has(g.toLowerCase()));!t.names.length&&f.length&&(t.names=f.slice(0,3)),t.intent==="group"&&(t.group=d.group||(t.kind==="meeting"?"person":"month"),t.terms=t.terms.filter(g=>!K.test(g)),t.limit=5),t.intent==="latest"&&(t.sort="newest",t.limit=5),t.intent==="earliest"&&(t.sort="oldest",t.limit=5),t.intent==="list"&&(t.limit=12),t.intent==="detail"&&(t.readFull=!0),t.intent==="people"&&(t.sort="newest",t.limit=3,t.readFull=!0,t.kind=t.kind||"meeting")}}const r={plan:t,rows:[],count:null,read:[],rounds:0,ms:0,attachment:null,how:Ae(t),...I};r.memory=se(c,{text:`${n} ${t.names.join(" ")}`,includeAmbient:!1,limit:5}).map(l=>l.text);const A=()=>u()-$>y.ms;try{r.rounds=1;const l=await s(t)||{};r.rows=(l.rows||[]).filter(d=>!T.has(d.id)),r.count=Number.isFinite(l.count)?Math.max(0,l.count-((l.rows||[]).length-r.rows.length)):r.rows.length,r.groups=t.group==="person"?xe(l.groups,v):l.groups||null}catch{r.rows=[]}if(!r.rows.length&&!r.groups?.length&&a&&r.rounds<y.rounds&&!A()){r.rounds=2;try{const l=await a(n);r.rows=(l?.modes?.hybrid||[]).filter(d=>!d.echo&&!T.has(d.id)).slice(0,t.limit),r.how=`${r.how}; nothing matched that exactly, so a wider search of everything`}catch{}}if(!r.rows.length&&!t.target&&!r.groups?.length)return r.ms=u()-$,r.memory.length&&(r.attachment=P(n,r,{now:$})),r;const Z=["count","group"].includes(t.intent)?0:["latest","earliest","detail","people"].includes(t.intent)?1:y.records,ee=t.target?[{id:t.target}]:r.rows.filter(l=>!String(l.id).startsWith("memory:")).slice(0,Z),j=O({windowTokens:E,reserveTokens:450}),N=async l=>{const d=await h(l.id).catch(()=>null);if(!d?.text)return;const f=Se(d.text),g=i&&t.readFull&&j>0,x=g?be(oe(d.text,{maxChars:j}),t,y.parts):ye(d.text,t,{chunkChars:y.chunkChars,max:t.readFull?y.chunks:2}).map(b=>({...b,index:Math.floor(b.at/y.chunkChars)+1,of:Math.ceil(d.text.length/y.chunkChars)}));let C=[];i&&t.readFull&&t.intent!=="people"&&(C=(await re(x,S=>i(ie({question:n,title:d.title||l.title,date:L(d.date||l.date),speakers:f,part:S}),{maxTokens:g?400:220}),{concurrency:w,late:A})).map((S,M)=>S&&x.length>1?`[part ${x[M].index}/${x[M].of}] ${S}`:S).filter(Boolean)),C.length||(C=x.map(b=>b.text.replace(/\s+/g," ").trim()).filter(Boolean)),r.read.push({id:d.id||l.id,title:d.title||l.title,date:d.date||l.date,notes:C,chunks:x.length,of:x[0]?.of||1,speakers:f})};for(const l of ee){if(A())break;await N(l)}if(i&&y.check!==!1&&a&&r.rounds<y.rounds&&!A()&&!["count","group","people","latest","earliest"].includes(t.intent)&&(r.read.length||r.rows.length)){const l=P(n,r,{now:$}),d=l?await i(Ee(n,l.text),{maxTokens:80}).catch(()=>""):"",f=B(d,Y);if(r.verdict=f?.answered||null,f?.answered==="no"){r.rounds+=1;const g=[n,f.missing].filter(Boolean).join(" ").slice(0,600);try{const C=((await a(g))?.modes?.hybrid||[]).filter(b=>!b.echo&&!T.has(b.id)&&!r.rows.some(S=>S.id===b.id));if(C.length){r.rows.push(...C.slice(0,5)),r.how=`${r.how}; what that found did not answer it, so a wider search${f.missing?` for "${String(f.missing).slice(0,80)}"`:""}`;const b=C.find(S=>!String(S.id).startsWith("memory:"));b&&!A()&&await N(b)}}catch{}}}const D=O({windowTokens:e,reserveTokens:1024,frameTokens:900});if(D>0&&r.read.length){r.fitted=!0;const l=Math.floor(D/r.read.length);for(const d of r.read)d.notes=await ae(d.notes,{question:n,budgetChars:l,batchChars:j||l,complete:i?f=>i(f,{maxTokens:500}):null,concurrency:w,late:A})}return r.ms=u()-$,r.attachment=P(n,r,{now:$}),r}function P(n,s,{now:h=Date.now()}={}){const a=[];s.memory?.length&&a.push("Kept by the person (memory):",...s.memory.map(o=>`- [memory] ${o}`),""),a.push(`Searched ${s.how}${s.count!=null&&s.plan.intent!=="detail"?` — ${s.count} found`:""}.`),s.groups?.length&&a.push("","Grouped:",...s.groups.slice(0,24).map(o=>`- ${o.key}: ${o.count}`)),s.rows.length&&(a.push("","Found:"),s.rows.slice(0,12).forEach((o,p)=>a.push(`${p+1}. [${o.id}] ${o.title||""}${o.date?` — ${L(o.date)}`:""}${o.snippet?` — ${String(o.snippet).replace(/\s+/g," ").slice(0,160)}`:""}`)));for(const o of s.read)a.push("",`Read [${o.id}] "${o.title}"${o.date?` (${L(o.date)})`:""} — ${o.chunks} of ${o.of} part${o.of===1?"":"s"}:`),(s.plan.intent==="people"||o.speakers?.length>1)&&a.push(` Speakers (lines spoken): ${(o.speakers||[]).map(p=>`${p.name} (${p.lines})`).join(", ")||"none recorded"}`),s.plan.intent!=="people"&&a.push(...o.notes.map(p=>` ${s.fitted?p:p.slice(0,1600)}`));if(!s.rows.length&&!s.read.length&&!s.memory?.length&&!s.groups?.length)return null;const c=`(ALREADY RESEARCHED the person's own data for the question below — the whole store, not a guess. ${s.plan.intent==="latest"?"The FIRST found item is the most recent; answer with its date.":s.plan.intent==="earliest"?"The FIRST found item is the earliest; answer with its date.":s.plan.intent==="count"?"Answer with the count found.":s.plan.intent==="group"?s.groups?.length?"Answer from the grouped counts; they cover the whole store.":"The store could not group this; say so, and answer from what was found.":s.plan.intent==="people"?"Answer with the speakers listed for the meeting read.":"Answer from what was read."} Cite the [id] you use. If the answer is not here, say it was not found in their data; never guess and never say you have no access.)
12
+ ${a.length>d?`${a.slice(0,d)}
13
+ …`:a}`}function Re(n){const s={meeting:"meetings",note:"notes",chat:"chats"}[n.kind]||"records",d=n.names.length?` naming ${n.names.join(" and ")}`:"",a=n.terms.length?` about ${n.terms.slice(0,6).join(", ")}`:"",r=[n.after?`after ${E(n.after-864e5)}`:"",n.before?`before ${E(n.before)}`:"",n.since?`since ${E(n.since)}`:""].filter(Boolean).join(", "),c=n.sort==="newest"?", newest first":n.sort==="oldest"?", oldest first":", most relevant first";return`${s}${d}${a}${r?` ${r}`:""}${c}`}async function Ue(n,{query:s,readText:d,searchModes:a=null,complete:r=null,memories:c=[],previous:o=null,knownNames:p=[],limits:k=F,now:u=()=>Date.now(),mapWindow:x=0,answerWindow:e=0,parallel:b=1,corrections:m=null,self:L=""}={}){const $=u(),y={...F,...k},N=he(m),j=new Set(N.notNames),R=new Set(N.hidden),t=$e(n,{previous:o,knownNames:p.filter(l=>!j.has(String(l).toLowerCase())),now:$}),te=String(n||""),D={framedBy:"rules"};if(t.names=t.names.filter(l=>!j.has(String(l).toLowerCase())),t.target&&R.has(t.target)&&(t.target=null),r&&y.modelFrame!==!1&&t.intent==="find"&&!t.followUp&&!t.target){const l=await r(ve(n),{maxTokens:90}).catch(()=>""),h=G(l,Z);if(h){D.framedBy="model",h.intent&&h.intent!=="find"&&(t.intent=h.intent),!t.kind&&h.kind&&(t.kind=h.kind);const g=(h.names||[]).map(f=>String(f).trim()).filter(f=>f&&te.toLowerCase().includes(f.toLowerCase())&&!j.has(f.toLowerCase()));!t.names.length&&g.length&&(t.names=g.slice(0,3)),t.intent==="group"&&(t.group=h.group||(t.kind==="meeting"?"person":"month"),t.terms=t.terms.filter(f=>!V.test(f)),t.limit=5),t.intent==="latest"&&(t.sort="newest",t.limit=5),t.intent==="earliest"&&(t.sort="oldest",t.limit=5),t.intent==="list"&&(t.limit=12),t.intent==="detail"&&(t.readFull=!0),t.intent==="people"&&(t.sort="newest",t.limit=3,t.readFull=!0,t.kind=t.kind||"meeting")}}const i={plan:t,rows:[],count:null,read:[],rounds:0,ms:0,attachment:null,how:Re(t),...D};i.memory=ie(c,{text:`${n} ${t.names.join(" ")}`,includeAmbient:!1,limit:5}).map(l=>l.text);const C=()=>u()-$>y.ms;try{i.rounds=1;const l=await s(t)||{};i.rows=(l.rows||[]).filter(h=>!R.has(h.id)),i.count=Number.isFinite(l.count)?Math.max(0,l.count-((l.rows||[]).length-i.rows.length)):i.rows.length,i.groups=t.group==="person"?Le(l.groups,L):l.groups||null}catch{i.rows=[]}if(!i.rows.length&&!i.groups?.length&&a&&i.rounds<y.rounds&&!C()){i.rounds=2;try{const l=await a(n);i.rows=(l?.modes?.hybrid||[]).filter(h=>!h.echo&&!R.has(h.id)).slice(0,t.limit),i.how=`${i.how}; nothing matched that exactly, so a wider search of everything`}catch{}}if(!i.rows.length&&!t.target&&!i.groups?.length)return i.ms=u()-$,i.memory.length&&(i.attachment=_(n,i,{now:$})),i;const ne=["count","group"].includes(t.intent)?0:["latest","earliest","detail","people"].includes(t.intent)?1:y.records,se=t.target?[{id:t.target}]:i.rows.filter(l=>!String(l.id).startsWith("memory:")).slice(0,ne),I=q({windowTokens:x,reserveTokens:450}),M=async l=>{const h=await d(l.id).catch(()=>null),g=h?.text?H(h.text):"",f=h?.text?{...h,text:ue(e)?Fe(g):g}:h;if(!f?.text)return;const P=Ee(f.text),A=r&&t.readFull&&I>0,w=A?Se(ae(f.text,{maxChars:I}),t,y.parts):xe(f.text,t,{chunkChars:y.chunkChars,max:t.readFull?y.chunks:2}).map(v=>({...v,index:Math.floor(v.at/y.chunkChars)+1,of:Math.ceil(f.text.length/y.chunkChars)}));let S=[];r&&t.readFull&&t.intent!=="people"&&(S=(await ce(w,T=>r(le({question:n,title:f.title||l.title,date:E(f.date||l.date),speakers:P,part:T}),{maxTokens:A?400:220}),{concurrency:b,late:C})).map((T,U)=>T&&w.length>1?`[part ${w[U].index}/${w[U].of}] ${T}`:T).filter(Boolean)),S.length||(S=w.map(v=>v.text.replace(/\s+/g," ").trim()).filter(Boolean)),i.read.push({id:f.id||l.id,title:f.title||l.title,date:f.date||l.date,notes:S,chunks:w.length,of:w[0]?.of||1,speakers:P})};for(const l of se){if(C())break;await M(l)}if(r&&y.check!==!1&&a&&i.rounds<y.rounds&&!C()&&!["count","group","people","latest","earliest"].includes(t.intent)&&(i.read.length||i.rows.length)){const l=_(n,i,{now:$}),h=l?await r(Te(n,l.text),{maxTokens:80}).catch(()=>""):"",g=G(h,ee);if(i.verdict=g?.answered||null,g?.answered==="no"){i.rounds+=1;const f=[n,g.missing].filter(Boolean).join(" ").slice(0,600);try{const A=((await a(f))?.modes?.hybrid||[]).filter(w=>!w.echo&&!R.has(w.id)&&!i.rows.some(S=>S.id===w.id));if(A.length){i.rows.push(...A.slice(0,5)),i.how=`${i.how}; what that found did not answer it, so a wider search${g.missing?` for "${String(g.missing).slice(0,80)}"`:""}`;const w=A.find(S=>!String(S.id).startsWith("memory:"));w&&!C()&&await M(w)}}catch{}}}const O=q({windowTokens:e,reserveTokens:1024,frameTokens:900});if(O>0&&i.read.length){i.fitted=!0;const l=Math.floor(O/i.read.length);for(const h of i.read)h.notes=await de(h.notes,{question:n,budgetChars:l,batchChars:I||l,complete:r?g=>r(g,{maxTokens:500}):null,concurrency:b,late:C})}return i.ms=u()-$,i.attachment=_(n,i,{now:$}),i}function _(n,s,{now:d=Date.now()}={}){const a=[];s.memory?.length&&a.push("Kept by the person (memory):",...s.memory.map(o=>`- [memory] ${o}`),""),a.push(`Searched ${s.how}${s.count!=null&&s.plan.intent!=="detail"?` — ${s.count} found`:""}.`),s.groups?.length&&a.push("","Grouped:",...s.groups.slice(0,24).map(o=>`- ${o.key}: ${o.count}`)),s.rows.length&&(a.push("","Found:"),s.rows.slice(0,12).forEach((o,p)=>a.push(`${p+1}. [${o.id}] ${o.title||""}${o.date?` — ${E(o.date)}`:""}${o.snippet?` — ${H(String(o.snippet).replace(/\s+/g," ")).slice(0,160)}`:""}`)));for(const o of s.read)a.push("",`Read [${o.id}] "${o.title}"${o.date?` (${E(o.date)})`:""} — ${o.chunks} of ${o.of} part${o.of===1?"":"s"}:`),(s.plan.intent==="people"||o.speakers?.length>1)&&a.push(` Speakers (lines spoken): ${(o.speakers||[]).map(p=>`${p.name} (${p.lines})`).join(", ")||"none recorded"}`),s.plan.intent!=="people"&&a.push(...o.notes.map(p=>` ${s.fitted?p:p.slice(0,1600)}`));if(!s.rows.length&&!s.read.length&&!s.memory?.length&&!s.groups?.length)return null;const c=`(ALREADY RESEARCHED the person's own data for the question below — the whole store, not a guess. ${s.plan.intent==="latest"?"The FIRST found item is the most recent; answer with its date.":s.plan.intent==="earliest"?"The FIRST found item is the earliest; answer with its date.":s.plan.intent==="count"?"Answer with the count found.":s.plan.intent==="group"?s.groups?.length?"Answer from the grouped counts; they cover the whole store.":"The store could not group this; say so, and answer from what was found.":s.plan.intent==="people"?"Answer with the speakers listed for the meeting read.":"Answer from what was read."} Cite the [id] you use. If the answer is not here, say it was not found in their data; never guess and never say you have no access.)
14
14
 
15
15
  ${a.join(`
16
- `)}`;return{id:`prefetch_research_${h}`,kind:"prefetch",prefetch:"personal",title:"Researched your own data",text:c,chars:c.length}}export{Y as EVIDENCE_SCHEMA,V as FRAME_SCHEMA,R as RESEARCH_LIMITS,ye as chunksFor,we as dateIn,Ae as describePlan,Ee as evidencePrompt,Ce as framePrompt,ge as frameQuestion,xe as peopleGroups,Pe as research,P as researchAttachment,Se as speakersIn};
16
+ `)}`;return{id:`prefetch_research_${d}`,kind:"prefetch",prefetch:"personal",title:"Researched your own data",text:c,chars:c.length}}function Fe(n){return String(n||"").replace(/^(\s*)User:\s/gm,"$1(they asked) ").replace(/^(\s*)Assistant:\s/gm,"$1(the answer was) ")}export{ee as EVIDENCE_SCHEMA,Z as FRAME_SCHEMA,F as RESEARCH_LIMITS,xe as chunksFor,ke as dateIn,Re as describePlan,Te as evidencePrompt,ve as framePrompt,$e as frameQuestion,Le as peopleGroups,Fe as quotedTurns,Ue as research,_ as researchAttachment,Ee as speakersIn};
@@ -0,0 +1 @@
1
+ import{needsWhole as $}from"./digest.js";import{lookupSubject as I,prefetchPlan as C,answeredByPrefetch as D}from"./prefetch.js";import{partChars as E,STITCH_LIMITS as _}from"./stitch.js";import{isSmallWindow as x,FIT_HEADROOM as L,SMALL_WINDOW_ROUNDS as v}from"./context-window.js";const P=4,W={device:3,api:2,agent:8};function V({question:o="",sources:t=[],fixedTokens:n=0,target:l={}}={}){const c=l.kind||"api",a=Number(l.window)||0,s=x(a),d=$(o),g=Math.max(1,Number(l.concurrency)||(c==="device"?1:4)),b=Number(l.secondsPerCall)||W[c]||2,i=(Array.isArray(t)?t:[]).filter(Boolean).map(e=>({...e,chars:Math.max(0,Number(e.chars)||0)})),m=a?Math.floor(a*L)-(Number(l.reserve)||1024)-(Number(n)||0):1/0,y=Number.isFinite(m)?Math.max(0,m)*P:1/0,u=new Map,h=new Set;let f=y;for(let e=!0;e;){e=!1;const r=i.filter(w=>!h.has(w.id)),p=r.length?f/r.length:0;for(const w of r)w.chars<=p&&(h.add(w.id),f-=w.chars,e=!0)}const T=i.filter(e=>!h.has(e.id)).reduce((e,r)=>e+r.chars,0);for(const e of i)u.set(e.id,h.has(e.id)?e.chars:Math.floor(f*e.chars/(T||1)));const k=E({windowTokens:a,reserveTokens:450})||0,M=i.map(e=>{const r={id:e.id,kind:e.kind,title:e.title||"",chars:e.chars,share:u.get(e.id)};if(c==="agent")return{...r,how:"agent",calls:0,why:"an agent reads it itself — handed the material, not a digest"};if(h.has(e.id)||!Number.isFinite(y))return{...r,how:"whole",calls:0,why:"it fits"};if(!s)return{...r,how:"merge",calls:Math.ceil(e.chars/Math.max(1,r.share)),why:"a large window: what does not fit is merged by the model"};if(d&&k>0){const p=Math.min(_.parts,Math.ceil(e.chars/k)),w=Math.ceil(e.chars/k),R=Math.max(1,Math.ceil(p/4));return{...r,how:"digest",parts:p,calls:p+R,unread:Math.max(0,w-p),why:"the question needs all of it, and it does not fit: read in parts, the notes combined"}}return{...r,how:"cut",calls:0,why:d?"no room to read it in parts: the parts that bear on the question":"a focused question: the parts that bear on it, by relevance"}}),A=i.some(e=>e.prefetched),O=c==="agent"?{offer:!0,rounds:null,why:"an agent keeps its own tools"}:s&&A?{offer:!1,rounds:1,why:"a small window, and a prefetch already answered"}:s?{offer:!0,rounds:v,why:"a small window: one tool round, then the answer"}:{offer:!0,rounds:null,why:""},N=M.reduce((e,r)=>e+(r.calls||0),0),S=Math.round((Math.ceil(N/g)+1)*b);return{sources:M,tools:O,estimate:{calls:N+1,seconds:S},say:F(M,S)}}function F(o,t){const n=o.filter(s=>s.how==="digest");if(!n.length)return"";const l=n.length===1?`"${n[0].title||"what is attached"}"`:`${n.length} attachments`,c=n.reduce((s,d)=>s+d.parts,0),a=n.reduce((s,d)=>s+(d.unread||0),0);return`Reading all of ${l} in ${c} part${c===1?"":"s"} first, so the answer covers the whole of it${a?` (the last ${a} part${a===1?"":"s"} will not fit)`:""} — about ${t} s.`}const q=/\b(?:schedule|reschedule|remind(?:er)?|calendar|invite|e-?mail|inbox|send|reply|draft|create|add|save|write (?:a |an )?note|open|click|fill|book|order|cancel|delete|rename|move|upload|download|run|execute|deploy|commit|share|post)\b/i,H=/\b(?:find out|find more|more (?:info|information|details)|look into|latest|current(?:ly)?|today|tonight|tomorrow|right now|this (?:week|weekend|month|year)|price|prices|cost|stock|shares?|score|news|headlines?|weather|forecast|hours|near me|nearby|directions|traffic|flight|look (?:it |that )?up|search|google|website|link|url|https?:\/\/|who(?:'s| is| was| are)|where(?:'s| is| are)|when(?:'s| is| does| do))\b/i,U=/\b(?:my|mine|our|ours|we|us|did i|have i|i (?:said|asked|wrote|told|had|was)|remember|last time|earlier today|meetings?|notes?|transcripts?|conversations?|chats?)\b/i;function j(o){const t=String(o||"").trim();return t?q.test(t)||H.test(t)||U.test(t)||!!I(t):!1}const B=new Set(["weather","stock","news","page","web","research"]);function X(o=[]){return(Array.isArray(o)?o:[]).some(t=>t?.kind==="prefetch"&&B.has(t.prefetch)&&String(t.text||"").trim())}function K({window:o=0,question:t="",answered:n=!1}={}){return x(o)?n?{offer:!1,rounds:1,why:"a small window, and a prefetch already answered"}:j(t)?{offer:!0,rounds:v,why:"a small window: one tool round, then the answer"}:{offer:!1,rounds:1,why:"a small window, and a question that needs no tools"}:{offer:!0,rounds:null,why:""}}function Y({question:o="",previousText:t="",previousAnswer:n="",previous:l=null,reach:c=new Set,window:a=0,personal:s=!1,lookup:d=null,now:g=Date.now()}={}){const b=x(a),i=C({text:o,previous:l,previousText:t,previousAnswer:n,reach:c,research:!0,page:!0,lookup:d??b,now:g}),m=i.some(f=>["weather","stock","news","page","web","research"].includes(f.kind)),y=!!s&&!m,u=[];i.length&&u.push(`fetch first: ${i.map(f=>f.label||f.kind).join(", ")}`),s&&m&&u.push("a world fact — the person's history is not searched for it");const h=K({window:a,question:o,answered:i.length>0});return h.why&&u.push(h.why),{prefetch:i,world:m,research:y,tools:h,why:u}}export{D as answeredByPrefetch,V as planRetrieval,Y as planTurn,K as toolPlan,j as toolsWanted,X as worldAnswered};
package/sandbox-policy.js CHANGED
@@ -1 +1 @@
1
- import{EventError as L}from"./event.js";import{normalizeGrant as x}from"./sandbox-grant.js";import{SECRET_DIR_NAMES as P,SECRET_DIR_PAIRS as N}from"./secret-names.js";const R=Object.freeze(["none","process","container","kubernetes"]),S=Object.freeze(["open","allowlist","none","gateway"]),E=Object.freeze(["~/.chatpanel","~/.ssh","~/.gnupg","~/.aws","~/.azure","~/.config/gcloud","~/.kube","~/.netrc","~/.docker/config.json","~/.npmrc","~/.pypirc"]),g=e=>{let t=String(e||"").trim();for(;t.length>1&&(t.endsWith("/")||t.endsWith("\\"));)t=t.slice(0,-1);return t},_=(e,t)=>t&&(e==="~"||e.startsWith("~/")||e.startsWith("~\\"))?t+e.slice(1):e,m=e=>String(e||"").replace(/\\/g,"/"),b=(e,t)=>{const n=m(g(e)),r=m(g(t));return!!n&&!!r&&(n===r||n.startsWith(`${r}/`))},v=E.map(e=>m(g(e)).replace(/^~\//,"").split("/").filter(Boolean));function I(e,t=""){const n=m(g(_(g(e),t)));if(!n)return!1;for(const o of E)if(b(n,o)||t&&b(n,_(o,t)))return!0;const r=n.split("/").filter(Boolean).map(o=>o.toLowerCase());return v.some(o=>{for(let s=0;s+o.length<=r.length;s+=1)if(o.every((c,l)=>c.toLowerCase()===r[s+l]))return!0;return!1})}const $=Object.freeze([...[...P].map(e=>`~/**/${e}`),...N.map(([e,t])=>`~/**/${e}/${t}`),...[".env",".netrc","_netrc",".git-credentials",".pgpass",".my.cnf",".npmrc",".pypirc",".htpasswd",".terraformrc",".vault-token","credentials","credentials.toml","id_rsa","id_dsa","id_ecdsa","id_ed25519","*.pem","*.p12","*.pfx","*.jks","*.keystore","*.kdbx","*.ppk"].map(e=>`~/**/${e}`)]);function J(e,{home:t="",globs:n=[...E,...$]}={}){const r=m(g(_(g(e),t)));if(!r)return null;const o=r.split("/").filter(Boolean),s=m(g(t));for(const c of n){const l=m(g(c));if(l){if(l.startsWith("~/**/")){if(s&&!b(r,s))continue;const a=l.slice(5).split("/").filter(Boolean).map(z);for(let i=0;i+a.length<=o.length;i+=1)if(a.every((f,p)=>f.test(o[i+p])))return c;continue}if(b(r,_(l,t)))return c}}return null}function z(e){return new RegExp(`^${e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*")}$`,"i")}const W=".cache/chatpanel/ca-bundle.crt",ee=".cache/chatpanel/ca-bundle.pem";function te(e=""){const t=m(g(e));return t?`${t}/${W}`:`~/${W}`}const H=Object.freeze(["~/.npm","~/.cache","~/.local","~/Library/Caches","~/.nvm","~/.volta","~/.asdf","~/.nodenv","~/.bun","~/.deno","~/.pyenv","~/.rye","~/.pdm","~/.cargo","~/.rustup","~/go","~/.goenv","~/.m2","~/.gradle","~/.sdkman","~/.jenv","~/.gem","~/.rbenv","~/.bundle","~/.composer","~/.nuget","~/.dotnet","~/.stack","~/.ghcup","~/.opam","~/.pub-cache","~/.gitconfig","~/.config/git"]),D=Object.freeze(["/tmp","/private/tmp","~/.cache","~/.npm","~/.local/share/uv","~/.local/state"]),C=Object.freeze({codex:Object.freeze({hosts:["api.openai.com","chatgpt.com","auth.openai.com","*.openai.com"],write:["~/.codex"]}),claude:Object.freeze({hosts:["api.anthropic.com","*.anthropic.com","claude.ai","statsig.anthropic.com"],write:["~/.claude","~/.claude.json"],keychain:!0}),antigravity:Object.freeze({hosts:["*.googleapis.com","*.google.com","oauth2.googleapis.com"],write:["~/.gemini","~/.antigravity","~/.config/antigravity"]}),custom:Object.freeze({hosts:[],write:[]}),mcp:Object.freeze({hosts:[],write:[]}),extract:Object.freeze({hosts:[],write:[]}),"model-server":Object.freeze({hosts:["huggingface.co","*.huggingface.co","*.hf.co","cdn-lfs.huggingface.co","cas-bridge.xethub.hf.co","dl.chatpanel.net"],write:[]})}),T="~/Library/Keychains",K=/(^|\/)Keychains\/?$/,k=Object.freeze(["github.com","*.github.com","*.githubusercontent.com","gitlab.com","bitbucket.org","registry.npmjs.org","pypi.org","files.pythonhosted.org","crates.io","static.crates.io","proxy.golang.org","sum.golang.org","huggingface.co","*.huggingface.co"]),h=e=>!!e&&typeof e=="object"&&!Array.isArray(e),O=e=>Array.isArray(e)&&e.every(t=>typeof t=="string"&&t.length>0),d=(e,t)=>{if(!e)throw new L("SHAPE",t)},u=e=>[...new Set(e)];function j(e){d(h(e),"kit: must be an object"),d(typeof e.id=="string"&&e.id.length>0,"kit: id required"),d(h(e.network)&&S.includes(e.network.mode),`kit ${e.id}: network.mode must be one of ${S.join(", ")}`),d(O(e.network.allowedDomains||[]),`kit ${e.id}: network.allowedDomains must be string[]`),d(O(e.network.deniedDomains||[]),`kit ${e.id}: network.deniedDomains must be string[]`),d(h(e.filesystem),`kit ${e.id}: filesystem required`);for(const t of["allowWrite","denyWrite","allowRead","denyRead"])d(O(e.filesystem[t]||[]),`kit ${e.id}: filesystem.${t} must be string[]`);return d(O(e.filesystem.allowWrite)&&e.filesystem.allowWrite.length>0,`kit ${e.id}: filesystem.allowWrite must name at least the working directory`),e.image!=null&&d(typeof e.image=="string",`kit ${e.id}: image must be a string`),e.credentials!=null&&d(Array.isArray(e.credentials)&&e.credentials.every(t=>h(t)&&typeof t.name=="string"&&typeof t.forHost=="string"),`kit ${e.id}: credentials must be [{ name, forHost }]`),{id:e.id,kind:e.kind||"process",image:e.image||null,network:{mode:e.network.mode,allowedDomains:u(e.network.allowedDomains||[]),deniedDomains:u(e.network.deniedDomains||[])},filesystem:{allowWrite:u(e.filesystem.allowWrite),denyWrite:u(e.filesystem.denyWrite||[]),allowRead:u(e.filesystem.allowRead||[]),denyRead:u(e.filesystem.denyRead||[])},credentials:e.credentials||[],limits:h(e.limits)?{...e.limits}:{}}}import{normalizeGrant as pe,mergeGrants as ge,parseHostList as me}from"./sandbox-grant.js";const Y=e=>String(e).replace(/([\\/])\*$/,"$1**");function ne({engine:e="custom",cwd:t,mode:n="open",extraHosts:r=[],extraWrite:o=[],extraDenyRead:s=[],grant:c=null,home:l="",reads:a="enumerated",readOnly:i=!1}={}){const f=C[e]||C.custom;d(typeof t=="string"&&t.length>0,"kit: cwd required");const p=x(c);return j({id:`${e}:${n}`,kind:"process",network:{mode:n,allowedDomains:n==="open"?["*"]:n==="none"?[]:u([...f.hosts,...k,...r,...p.hosts]),deniedDomains:[]},filesystem:{allowWrite:u(i?[...D,...f.write]:[t,...D,...f.write,...[...o,...p.write].filter(A=>!I(A,l)).map(Y)]),denyWrite:[],allowRead:a==="inverted"?u([t,...H,...f.write,...f.keychain?[T]:[],...B({grant:p,extraWrite:o,cwd:t,home:l})]):[t],denyRead:u([...a==="inverted"?["~",...l?[l]:[]]:[],...[...E,...$].filter(A=>!(f.keychain&&K.test(A))),...s])}})}function U(e){if(!/[*?[{]/.test(e))return e;const t=e.split(/[\\/]/),n=t.findIndex(s=>/[*?[{]/.test(s)),r=e.includes("\\")&&!e.includes("/")?"\\":"/",o=t.slice(0,n).join(r);return o&&o!=="~"?o:""}function B({grant:e=null,extraWrite:t=[],cwd:n="",home:r=""}={}){const o=i=>r&&(i==="~"||i.startsWith("~/")||i.startsWith("~\\"))?r+i.slice(1):i,s=i=>{let f=String(i||"").trim();for(;f.length>1&&(f.endsWith("/")||f.endsWith("\\"));)f=f.slice(0,-1);return f},c=(i,f)=>i===f||i.startsWith(`${f}/`)||i.startsWith(`${f}\\`),l=s(o(n)),a=[];for(const i of[...x(e).write,...Array.isArray(t)?t:[]]){const f=U(s(o(s(i))));if(f&&!I(f,r)&&!(l&&c(f,l))&&!a.some(p=>c(f,p))){for(let p=a.length-1;p>=0;p--)c(a[p],f)&&a.splice(p,1);a.push(f)}}return a}function oe(e,{loopback:t=[],home:n="",platform:r="darwin"}={}){const o=j(e),s=l=>n&&l.startsWith("~")?n+l.slice(1):l,c=o.network.mode==="none"?[]:t.map(l=>`127.0.0.1:${l}`);return{network:{allowedDomains:u([...o.network.allowedDomains,...c]),deniedDomains:o.network.deniedDomains,allowLocalBinding:r==="darwin"&&c.length>0},filesystem:{denyRead:o.filesystem.denyRead.map(s),allowRead:o.filesystem.allowRead.map(s),allowWrite:o.filesystem.allowWrite.map(s),denyWrite:o.filesystem.denyWrite.map(s)}}}function re({layer:e="none",runtime:t=null,kitId:n=null,mode:r=null,reason:o=null,hosts:s=null}={}){return d(R.includes(e),`sandbox record: layer must be one of ${R.join(", ")}`),{layer:e,runtime:t,kit:n,mode:r,...e==="none"&&o?{reason:o}:{},...Array.isArray(s)&&s.length?{hosts:u(s)}:{}}}function G(e,{platform:t="darwin"}={}){const n=String(e);if(t==="win32"){d(!/[\r\n]/.test(n),"win32 command line: an argument holds a newline, which cmd.exe cannot carry");let r=n;if(n===""||/[ \t\v"]/.test(n)){r='"';for(let o=0;o<n.length;o++){let s=0;for(;o<n.length&&n[o]==="\\";)s++,o++;if(o===n.length){r+="\\".repeat(s*2);break}n[o]==='"'?r+="\\".repeat(s*2+1)+'"':r+="\\".repeat(s)+n[o]}r+='"'}return r.replace(/[()%!^"<>&|]/g,"^$&")}return n===""?"''":/^[A-Za-z0-9_\-./=:@%+,]+$/.test(n)?n:`'${n.replace(/'/g,"'\\''")}'`}const M=Object.freeze(["SSL_CERT_FILE","REQUESTS_CA_BUNDLE","CURL_CA_BUNDLE","GIT_SSL_CAINFO"]);function se(e={},{platform:t="darwin",caBundle:n=""}={}){const r={NODE_USE_ENV_PROXY:"1"};if(n)for(const o of M)e[o]||(r[o]=n);if(t==="linux")for(const o of["no_proxy","NO_PROXY"])typeof e[o]=="string"&&(r[o]=e[o].split(",").map(s=>s.trim()).filter(s=>s&&!/^(localhost|127\.0\.0\.1|::1|\[::1\])$/i.test(s)).join(","));return r}function ie(e,t=[],{platform:n="darwin"}={}){return[e,...t].map(r=>G(r,{platform:n})).join(" ")}const ae=/[\\/]+/,w=e=>String(e||"").replace(/\//g,"\\").replace(/\\+$/,"").toLowerCase(),q=e=>/^[a-z]:$/i.test(w(e))||w(e)==="";function y(e,t){const n=w(e),r=w(t);return!!r&&n!==r&&n.startsWith(r+"\\")}function F(e){const t=String(e||"").replace(/\//g,"\\").split("\\");if(t.length<2)return"";const n=t.findIndex(r=>r.toLowerCase()==="node_modules");return(n>0?t.slice(0,n):t.slice(0,-1)).join("\\")}function ce({kit:e,files:t=[],home:n}){d(typeof n=="string"&&n.length>0,"windows grants: home required");const r=a=>(a.startsWith("~")?n+a.slice(1):a).replace(/\//g,"\\"),o=[];for(const a of e?.filesystem?.allowWrite||[]){const i=r(a);!/^[a-z]:\\/i.test(i)&&!i.startsWith("\\\\")||(d(!q(i)&&w(i)!==w(n),`windows grants: a write on ${i} would hand the sandbox account the whole profile`),y(i,n)&&o.push(i))}const s=(a,i)=>i.some(f=>w(a)===w(f)||y(a,f)),c=[];for(const a of t){const i=F(a);i&&y(i,n)&&c.push(i)}for(const a of e?.filesystem?.allowRead||[]){const i=r(a);y(i,n)&&c.push(i)}const l=u(c).filter(a=>!s(a,o));return{read:l.filter(a=>!l.some(i=>i!==a&&y(a,i))),write:u(o)}}const X=Object.freeze(["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_BASE_URL","CLAUDE_CONFIG_DIR","OPENAI_API_KEY","OPENAI_BASE_URL","OPENAI_API_BASE","CODEX_HOME","GEMINI_API_KEY","GOOGLE_API_KEY","DEEPSEEK_API_KEY","DSH_HOME","OPENROUTER_API_KEY","GROQ_API_KEY","XAI_API_KEY","MISTRAL_API_KEY"]);function le({engine:e="custom",home:t,env:n={},base:r={},carry:o=X}={}){d(typeof t=="string"&&t.length>0,"windows env: home required");const s=t.replace(/\//g,"\\"),c=/^[a-z]:/i.test(s)?s.slice(0,2):"",l={USERPROFILE:s,...c?{HOMEDRIVE:c,HOMEPATH:s.slice(2)}:{}};for(const[a,i]of Object.entries(n))typeof i=="string"&&(r[a]!==i||o.includes(a))&&(l[a]=i);return e==="codex"&&!l.CODEX_HOME&&(l.CODEX_HOME=s+"\\.codex"),l}function fe(e,t){d(Array.isArray(e),"srt-win argv: must be an array");const n=e.indexOf("exec"),r=n>=0?e.indexOf("--",n+1):-1;d(n>=0&&r>n,"srt-win argv: expected `exec … -- <shell> <command>`");const o=new Set;for(let c=n+1;c<r;c++)e[c]==="--env"&&typeof e[c+1]=="string"&&o.add(e[c+1].split("=")[0].toUpperCase());const s=[];for(const[c,l]of Object.entries(t||{}))d(/^[A-Za-z_][A-Za-z0-9_]*$/.test(c),`srt-win env: bad key ${c}`),d(!/[\r\n]/.test(l),`srt-win env: ${c} holds a newline`),o.has(c.toUpperCase())||s.push("--env",`${c}=${l}`);return[...e.slice(0,r),...s,...e.slice(r)]}export{W as CA_BUNDLE_RELPATH,ee as CA_BUNDLE_RELPATH_LEGACY,D as COMMON_WRITE,k as DEVELOPER_HOSTS,C as ENGINE_KITS,S as NETWORK_MODES,R as SANDBOX_LAYERS,E as SECRET_PATHS,$ as SECRET_READ_GLOBS,H as TOOLCHAIN_READ,X as WINDOWS_CARRY_KEYS,te as caBundlePath,I as isSecretWritePath,ne as kitFor,ge as mergeGrants,pe as normalizeGrant,me as parseHostList,J as readDenialFor,se as sandboxEnvOverlay,re as sandboxRecord,ie as shellJoin,G as shellQuote,oe as toSrtSettings,y as underWindowsHome,j as validateKit,ce as windowsGrantsFor,F as windowsInstallRoot,le as windowsSandboxEnv,fe as withSrtWinEnv,B as writableRoots};
1
+ import{EventError as L}from"./event.js";import{normalizeGrant as S}from"./sandbox-grant.js";import{SECRET_DIR_NAMES as P,SECRET_DIR_PAIRS as v}from"./secret-names.js";const R=Object.freeze(["none","process","container","kubernetes"]),$=Object.freeze(["open","allowlist","none","gateway"]),_=Object.freeze(["~/.chatpanel","~/.ssh","~/.gnupg","~/.aws","~/.azure","~/.config/gcloud","~/.kube","~/.netrc","~/.docker/config.json","~/.npmrc","~/.pypirc"]),g=e=>{let t=String(e||"").trim();for(;t.length>1&&(t.endsWith("/")||t.endsWith("\\"));)t=t.slice(0,-1);return t},x=(e,t)=>t&&(e==="~"||e.startsWith("~/")||e.startsWith("~\\"))?t+e.slice(1):e,m=e=>String(e||"").replace(/\\/g,"/"),b=(e,t)=>{const n=m(g(e)),r=m(g(t));return!!n&&!!r&&(n===r||n.startsWith(`${r}/`))},N=_.map(e=>m(g(e)).replace(/^~\//,"").split("/").filter(Boolean));function I(e,t=""){const n=m(g(x(g(e),t)));if(!n)return!1;for(const o of _)if(b(n,o)||t&&b(n,x(o,t)))return!0;const r=n.split("/").filter(Boolean).map(o=>o.toLowerCase());return N.some(o=>{for(let s=0;s+o.length<=r.length;s+=1)if(o.every((a,l)=>a.toLowerCase()===r[s+l]))return!0;return!1})}const W=Object.freeze([...[...P].map(e=>`~/**/${e}`),...v.map(([e,t])=>`~/**/${e}/${t}`),...[".env",".netrc","_netrc",".git-credentials",".pgpass",".my.cnf",".npmrc",".pypirc",".htpasswd",".terraformrc",".vault-token","credentials","credentials.toml","id_rsa","id_dsa","id_ecdsa","id_ed25519","*.pem","*.p12","*.pfx","*.jks","*.keystore","*.kdbx","*.ppk"].map(e=>`~/**/${e}`)]);function ee(e,{home:t="",globs:n=[..._,...W]}={}){const r=m(g(x(g(e),t)));if(!r)return null;const o=r.split("/").filter(Boolean),s=m(g(t));for(const a of n){const l=m(g(a));if(l){if(l.startsWith("~/**/")){if(s&&!b(r,s))continue;const c=l.slice(5).split("/").filter(Boolean).map(z);for(let i=0;i+c.length<=o.length;i+=1)if(c.every((d,u)=>d.test(o[i+u])))return a;continue}if(b(r,x(l,t)))return a}}return null}function z(e){return new RegExp(`^${e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*")}$`,"i")}const D=".cache/chatpanel/ca-bundle.crt",te=".cache/chatpanel/ca-bundle.pem";function ne(e=""){const t=m(g(e));return t?`${t}/${D}`:`~/${D}`}const H=Object.freeze(["~/.npm","~/.cache","~/.local","~/Library/Caches","~/.nvm","~/.volta","~/.asdf","~/.nodenv","~/.bun","~/.deno","~/.pyenv","~/.rye","~/.pdm","~/.cargo","~/.rustup","~/go","~/.goenv","~/.m2","~/.gradle","~/.sdkman","~/.jenv","~/.gem","~/.rbenv","~/.bundle","~/.composer","~/.nuget","~/.dotnet","~/.stack","~/.ghcup","~/.opam","~/.pub-cache","~/.gitconfig","~/.config/git"]),k=Object.freeze(["/tmp","/private/tmp","~/.cache","~/.npm","~/.local/share/uv","~/.local/state"]),C=Object.freeze({codex:Object.freeze({hosts:["api.openai.com","chatgpt.com","auth.openai.com","*.openai.com"],write:["~/.codex"]}),claude:Object.freeze({hosts:["api.anthropic.com","*.anthropic.com","claude.ai","statsig.anthropic.com"],write:["~/.claude","~/.claude.json"],keychain:!0,sockets:["/tmp/cc-socks","/private/tmp/cc-socks"]}),antigravity:Object.freeze({hosts:["*.googleapis.com","*.google.com","oauth2.googleapis.com"],write:["~/.gemini","~/.antigravity","~/.config/antigravity"]}),custom:Object.freeze({hosts:[],write:[]}),mcp:Object.freeze({hosts:[],write:[]}),extract:Object.freeze({hosts:[],write:[]}),"model-server":Object.freeze({hosts:["huggingface.co","*.huggingface.co","*.hf.co","cdn-lfs.huggingface.co","cas-bridge.xethub.hf.co","dl.chatpanel.net"],write:[]})}),T="~/Library/Keychains",K=/(^|\/)Keychains\/?$/,Y=Object.freeze(["github.com","*.github.com","*.githubusercontent.com","gitlab.com","bitbucket.org","registry.npmjs.org","pypi.org","files.pythonhosted.org","crates.io","static.crates.io","proxy.golang.org","sum.golang.org","huggingface.co","*.huggingface.co"]),h=e=>!!e&&typeof e=="object"&&!Array.isArray(e),y=e=>Array.isArray(e)&&e.every(t=>typeof t=="string"&&t.length>0),f=(e,t)=>{if(!e)throw new L("SHAPE",t)},p=e=>[...new Set(e)];function j(e){f(h(e),"kit: must be an object"),f(typeof e.id=="string"&&e.id.length>0,"kit: id required"),f(h(e.network)&&$.includes(e.network.mode),`kit ${e.id}: network.mode must be one of ${$.join(", ")}`),f(y(e.network.allowedDomains||[]),`kit ${e.id}: network.allowedDomains must be string[]`),f(y(e.network.deniedDomains||[]),`kit ${e.id}: network.deniedDomains must be string[]`),f(h(e.filesystem),`kit ${e.id}: filesystem required`);for(const t of["allowWrite","denyWrite","allowRead","denyRead"])f(y(e.filesystem[t]||[]),`kit ${e.id}: filesystem.${t} must be string[]`);return f(y(e.filesystem.allowWrite)&&e.filesystem.allowWrite.length>0,`kit ${e.id}: filesystem.allowWrite must name at least the working directory`),f(y(e.network.unixSockets||[])&&(e.network.unixSockets||[]).every(t=>t.startsWith("/")&&t.replace(/\/+$/,"")!==""),`kit ${e.id}: network.unixSockets must be absolute folders, never /`),e.image!=null&&f(typeof e.image=="string",`kit ${e.id}: image must be a string`),e.credentials!=null&&f(Array.isArray(e.credentials)&&e.credentials.every(t=>h(t)&&typeof t.name=="string"&&typeof t.forHost=="string"),`kit ${e.id}: credentials must be [{ name, forHost }]`),{id:e.id,kind:e.kind||"process",image:e.image||null,network:{mode:e.network.mode,allowedDomains:p(e.network.allowedDomains||[]),deniedDomains:p(e.network.deniedDomains||[]),...(e.network.unixSockets||[]).length?{unixSockets:p(e.network.unixSockets)}:{}},filesystem:{allowWrite:p(e.filesystem.allowWrite),denyWrite:p(e.filesystem.denyWrite||[]),allowRead:p(e.filesystem.allowRead||[]),denyRead:p(e.filesystem.denyRead||[])},credentials:e.credentials||[],limits:h(e.limits)?{...e.limits}:{}}}import{normalizeGrant as ge,mergeGrants as me,parseHostList as we}from"./sandbox-grant.js";const U=e=>String(e).replace(/([\\/])\*$/,"$1**");function oe({engine:e="custom",cwd:t,mode:n="open",extraHosts:r=[],extraWrite:o=[],extraDenyRead:s=[],grant:a=null,home:l="",reads:c="enumerated",readOnly:i=!1,peers:d=!0}={}){const u=C[e]||C.custom;f(typeof t=="string"&&t.length>0,"kit: cwd required");const O=S(a);return j({id:`${e}:${n}`,kind:"process",network:{mode:n,allowedDomains:n==="open"?["*"]:n==="none"?[]:p([...u.hosts,...Y,...r,...O.hosts]),deniedDomains:[],unixSockets:d?[...u.sockets||[]]:[]},filesystem:{allowWrite:p(i?[...k,...u.write]:[t,...k,...u.write,...[...o,...O.write].filter(A=>!I(A,l)).map(U)]),denyWrite:[],allowRead:c==="inverted"?p([t,...H,...u.write,...u.keychain?[T]:[],...G({grant:O,extraWrite:o,cwd:t,home:l})]):[t],denyRead:p([...c==="inverted"?["~",...l?[l]:[]]:[],...[..._,...W].filter(A=>!(u.keychain&&K.test(A))),...s])}})}function B(e){if(!/[*?[{]/.test(e))return e;const t=e.split(/[\\/]/),n=t.findIndex(s=>/[*?[{]/.test(s)),r=e.includes("\\")&&!e.includes("/")?"\\":"/",o=t.slice(0,n).join(r);return o&&o!=="~"?o:""}function G({grant:e=null,extraWrite:t=[],cwd:n="",home:r=""}={}){const o=i=>r&&(i==="~"||i.startsWith("~/")||i.startsWith("~\\"))?r+i.slice(1):i,s=i=>{let d=String(i||"").trim();for(;d.length>1&&(d.endsWith("/")||d.endsWith("\\"));)d=d.slice(0,-1);return d},a=(i,d)=>i===d||i.startsWith(`${d}/`)||i.startsWith(`${d}\\`),l=s(o(n)),c=[];for(const i of[...S(e).write,...Array.isArray(t)?t:[]]){const d=B(s(o(s(i))));if(d&&!I(d,r)&&!(l&&a(d,l))&&!c.some(u=>a(d,u))){for(let u=c.length-1;u>=0;u--)a(c[u],d)&&c.splice(u,1);c.push(d)}}return c}function re(e,{loopback:t=[],home:n="",platform:r="darwin"}={}){const o=j(e),s=l=>n&&l.startsWith("~")?n+l.slice(1):l,a=o.network.mode==="none"?[]:t.map(l=>`127.0.0.1:${l}`);return{network:{allowedDomains:p([...o.network.allowedDomains,...a]),deniedDomains:o.network.deniedDomains,allowLocalBinding:r==="darwin"&&a.length>0,...r==="darwin"&&o.network.unixSockets?.length?{allowUnixSockets:o.network.unixSockets}:{}},filesystem:{denyRead:o.filesystem.denyRead.map(s),allowRead:o.filesystem.allowRead.map(s),allowWrite:o.filesystem.allowWrite.map(s),denyWrite:o.filesystem.denyWrite.map(s)}}}function se({layer:e="none",runtime:t=null,kitId:n=null,mode:r=null,reason:o=null,hosts:s=null}={}){return f(R.includes(e),`sandbox record: layer must be one of ${R.join(", ")}`),{layer:e,runtime:t,kit:n,mode:r,...e==="none"&&o?{reason:o}:{},...Array.isArray(s)&&s.length?{hosts:p(s)}:{}}}function M(e,{platform:t="darwin"}={}){const n=String(e);if(t==="win32"){f(!/[\r\n]/.test(n),"win32 command line: an argument holds a newline, which cmd.exe cannot carry");let r=n;if(n===""||/[ \t\v"]/.test(n)){r='"';for(let o=0;o<n.length;o++){let s=0;for(;o<n.length&&n[o]==="\\";)s++,o++;if(o===n.length){r+="\\".repeat(s*2);break}n[o]==='"'?r+="\\".repeat(s*2+1)+'"':r+="\\".repeat(s)+n[o]}r+='"'}return r.replace(/[()%!^"<>&|]/g,"^$&")}return n===""?"''":/^[A-Za-z0-9_\-./=:@%+,]+$/.test(n)?n:`'${n.replace(/'/g,"'\\''")}'`}const q=Object.freeze(["SSL_CERT_FILE","REQUESTS_CA_BUNDLE","CURL_CA_BUNDLE","GIT_SSL_CAINFO"]);function ie(e={},{platform:t="darwin",caBundle:n=""}={}){const r={NODE_USE_ENV_PROXY:"1"};if(n)for(const o of q)e[o]||(r[o]=n);if(t==="linux")for(const o of["no_proxy","NO_PROXY"])typeof e[o]=="string"&&(r[o]=e[o].split(",").map(s=>s.trim()).filter(s=>s&&!/^(localhost|127\.0\.0\.1|::1|\[::1\])$/i.test(s)).join(","));return r}function ce(e,t=[],{platform:n="darwin"}={}){return[e,...t].map(r=>M(r,{platform:n})).join(" ")}const ae=/[\\/]+/,w=e=>String(e||"").replace(/\//g,"\\").replace(/\\+$/,"").toLowerCase(),F=e=>/^[a-z]:$/i.test(w(e))||w(e)==="";function E(e,t){const n=w(e),r=w(t);return!!r&&n!==r&&n.startsWith(r+"\\")}function X(e){const t=String(e||"").replace(/\//g,"\\").split("\\");if(t.length<2)return"";const n=t.findIndex(r=>r.toLowerCase()==="node_modules");return(n>0?t.slice(0,n):t.slice(0,-1)).join("\\")}function le({kit:e,files:t=[],home:n}){f(typeof n=="string"&&n.length>0,"windows grants: home required");const r=c=>(c.startsWith("~")?n+c.slice(1):c).replace(/\//g,"\\"),o=[];for(const c of e?.filesystem?.allowWrite||[]){const i=r(c);!/^[a-z]:\\/i.test(i)&&!i.startsWith("\\\\")||(f(!F(i)&&w(i)!==w(n),`windows grants: a write on ${i} would hand the sandbox account the whole profile`),E(i,n)&&o.push(i))}const s=(c,i)=>i.some(d=>w(c)===w(d)||E(c,d)),a=[];for(const c of t){const i=X(c);i&&E(i,n)&&a.push(i)}for(const c of e?.filesystem?.allowRead||[]){const i=r(c);E(i,n)&&a.push(i)}const l=p(a).filter(c=>!s(c,o));return{read:l.filter(c=>!l.some(i=>i!==c&&E(c,i))),write:p(o)}}const V=Object.freeze(["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_BASE_URL","CLAUDE_CONFIG_DIR","OPENAI_API_KEY","OPENAI_BASE_URL","OPENAI_API_BASE","CODEX_HOME","GEMINI_API_KEY","GOOGLE_API_KEY","DEEPSEEK_API_KEY","DSH_HOME","OPENROUTER_API_KEY","GROQ_API_KEY","XAI_API_KEY","MISTRAL_API_KEY"]);function de({engine:e="custom",home:t,env:n={},base:r={},carry:o=V}={}){f(typeof t=="string"&&t.length>0,"windows env: home required");const s=t.replace(/\//g,"\\"),a=/^[a-z]:/i.test(s)?s.slice(0,2):"",l={USERPROFILE:s,...a?{HOMEDRIVE:a,HOMEPATH:s.slice(2)}:{}};for(const[c,i]of Object.entries(n))typeof i=="string"&&(r[c]!==i||o.includes(c))&&(l[c]=i);return e==="codex"&&!l.CODEX_HOME&&(l.CODEX_HOME=s+"\\.codex"),l}function fe(e,t){f(Array.isArray(e),"srt-win argv: must be an array");const n=e.indexOf("exec"),r=n>=0?e.indexOf("--",n+1):-1;f(n>=0&&r>n,"srt-win argv: expected `exec … -- <shell> <command>`");const o=new Set;for(let a=n+1;a<r;a++)e[a]==="--env"&&typeof e[a+1]=="string"&&o.add(e[a+1].split("=")[0].toUpperCase());const s=[];for(const[a,l]of Object.entries(t||{}))f(/^[A-Za-z_][A-Za-z0-9_]*$/.test(a),`srt-win env: bad key ${a}`),f(!/[\r\n]/.test(l),`srt-win env: ${a} holds a newline`),o.has(a.toUpperCase())||s.push("--env",`${a}=${l}`);return[...e.slice(0,r),...s,...e.slice(r)]}export{D as CA_BUNDLE_RELPATH,te as CA_BUNDLE_RELPATH_LEGACY,k as COMMON_WRITE,Y as DEVELOPER_HOSTS,C as ENGINE_KITS,$ as NETWORK_MODES,R as SANDBOX_LAYERS,_ as SECRET_PATHS,W as SECRET_READ_GLOBS,H as TOOLCHAIN_READ,V as WINDOWS_CARRY_KEYS,ne as caBundlePath,I as isSecretWritePath,oe as kitFor,me as mergeGrants,ge as normalizeGrant,we as parseHostList,ee as readDenialFor,ie as sandboxEnvOverlay,se as sandboxRecord,ce as shellJoin,M as shellQuote,re as toSrtSettings,E as underWindowsHome,j as validateKit,le as windowsGrantsFor,X as windowsInstallRoot,de as windowsSandboxEnv,fe as withSrtWinEnv,G as writableRoots};
package/search-modes.js CHANGED
@@ -1,9 +1,9 @@
1
- import{fuseRRF as F}from"./rrf.js";import{lexicalPlan as T}from"./recall.js";import{recall as Q}from"./memory.js";const Z=Object.freeze(["memory","keyword","graph","hybrid"]),W=new Set("i im ive id ill the a an this that these those what who whom whose which when where why how is are was were do does did can could will would should my your our their his her its we you he she they it me him them us yes no ok okay hi hello hey thanks please sure also and but or so if then monday tuesday wednesday thursday friday saturday sunday january february march april may june july august september october november december today tomorrow yesterday chap chapel chatpanel gemini nano claude codex speaker note notes chat chats meeting meetings summary topics action items met meet saw see called call asked ask told tell emailed email texted text messaged pinged ping spoke talked thanks thank dear cc per via with from here there now sorry great sure maybe perhaps still just only even also yet here's there's let please".split(/\s+/));function M(o,{max:a=12,midSentence:n=!1,exclude:r=[]}={}){const t=new Map,g=new Set(r.map(l=>String(l).toLowerCase()).filter(Boolean)),k=/\b([A-Z][a-z][A-Za-z'-]+(?:\s+[A-Z][a-z][A-Za-z'-]+){0,2})\b/g,d=String(o||"");for(const l of d.matchAll(k)){if(n&&/(^|[.!?:|\n"“]\s*)$/.test(d.slice(Math.max(0,l.index-3),l.index)))continue;const v=l[1].split(/\s+/).filter(i=>!W.has(i.toLowerCase().replace(/'s$/,"")));if(!v.length)continue;const S=v.join(" ").replace(/'s$/,"");if(S.length<3)continue;const b=S.toLowerCase();if(![...g].some(i=>b===i||b.split(" ").some(h=>i.split(" ").includes(h)))&&(t.set(b,t.get(b)||{name:S,count:0}),t.get(b).count+=1,t.size>=a*2))break}return[...t.values()].sort((l,v)=>v.count-l.count).slice(0,a).map(l=>l.name)}function I(o,{plan:a=null}={}){const n=(a?.terms?.length?a.terms:T(o).terms).map(t=>String(t).toLowerCase().replace(/[^a-z0-9]/g,"")).filter(t=>t.length>=2),r=new Set(n);for(const t of n)t.length>=7&&r.add(t.slice(0,5));return[...r].slice(0,12)}const q=o=>o?.sinceAt||0;function B(o,a){const n=I(o).filter(t=>t.length>=4);if(n.length<2)return!1;const r=String(a||"").toLowerCase();return n.filter(t=>r.includes(t)).length/n.length>=.8}const X=500;function N(o){const a=(n,r)=>[...new Set((Array.isArray(n)?n:[]).map(r).filter(Boolean))].slice(-X);return{notNames:a(o?.notNames,n=>String(n||"").replace(/\s+/g," ").trim().toLowerCase().slice(0,80)),hidden:a(o?.hidden,n=>String(n||"").trim().slice(0,200))}}function te(o,{op:a,value:n}){const r=N(o),t=String(n||"").trim();return t?a==="not-a-name"?N({...r,notNames:[...r.notNames,t]}):a==="undo-name"?{...r,notNames:r.notNames.filter(g=>g!==t.toLowerCase())}:a==="hide"?N({...r,hidden:[...r.hidden,t]}):a==="unhide"?{...r,hidden:r.hidden.filter(g=>g!==t)}:r:r}async function G(o,a,{decide:n,k:r=6}={}){const t=a.slice(0,r);if(!n||!t.length)return{reranked:a,decision:{verdict:"unknown"}};const g=[`Question: ${String(o).slice(0,400)}`,"",...t.map((i,h)=>`[${h+1}] ${i.title}: ${String(i.snippet||"").replace(/\s+/g," ").slice(0,280)}`)].join(`
2
- `),k={};t.forEach((i,h)=>{k[`p${h+1}`]={type:"score",instructions:`How well does passage [${h+1}] answer the question? A passage that only repeats the question, or says it cannot tell, does NOT answer it.`,options:["no","partly","answers it"]}}),k.answer={type:"choice",instructions:'Which passage gives the answer itself (a name, a fact, a date)? "none" if none does.',options:[...t.map((i,h)=>String(h+1)),"none"]};let d=null;try{d=await n({state:g,questions:k})}catch{d=null}const l=d?.answers;if(!l)return{reranked:a,decision:{verdict:"unknown"}};const v=t.map((i,h)=>({...i,relevance:Number(l[`p${h+1}`]?.value??0),at:h})).sort((i,h)=>h.relevance-i.relevance||i.at-h.at).map(({at:i,...h})=>h),S=String(l.answer?.value??"none"),b=S==="none"?null:t[Number(S)-1];return{reranked:[...v,...a.slice(r)],decision:b?{verdict:"found",id:b.id,title:b.title,by:d.model||"model",calibrated:d.calibrated!==!1}:{verdict:"not-found",by:d.model||"model",calibrated:d.calibrated!==!1}}}async function se(o,{lexical:a,decide:n=null,corrections:r=null,memories:t=[],self:g="",excludeId:k=null,plan:d=null,limit:l=10,modes:v=Z,hops:S=5,now:b=()=>Date.now()}={}){const i=new Set(v),h=N(r),j=new Set(h.hidden),R=async s=>(await a(s)||[]).filter(m=>!j.has(m.id)),A=d||T(o),O={chats:"chat",notes:"note",meetings:"meeting"}[A.scope]||"",u={plan:{terms:I(o,{plan:A}),scope:A.scope,since:A.since||""},modes:{},ms:{},errors:{}},E=async(s,m)=>{const w=b();try{u.modes[s]=await m()}catch(x){u.modes[s]=[],u.errors[s]=String(x?.message||x)}return u.ms[s]=b()-w,u.modes[s]},P=await E("memory",async()=>i.has("memory")||i.has("graph")||i.has("hybrid")?Q(t,{text:o,includeAmbient:!1,limit:l}).map((s,m)=>({id:`memory:${s.id}`,kind:"memory",title:s.text,date:s.updatedAt||0,snippet:s.text,score:1/(1+m)})).filter(s=>!j.has(s.id)):[]),C=await E("keyword",async()=>i.has("keyword")||i.has("graph")||i.has("hybrid")?(await R({terms:u.plan.terms,kind:O,sinceAt:q(A),limit:Math.max(l,20)+5})||[]).filter(s=>s.id!==k).map((s,m)=>({...s,echo:B(o,`${s.title}
3
- ${s.snippet||""}`),rank:m})).sort((s,m)=>Number(s.echo)-Number(m.echo)||s.rank-m.rank).map(({rank:s,...m},w)=>({...m,score:1/(1+w),...m.echo?{via:"an earlier time you asked"}:{}})):[]);await E("graph",async()=>{if(!i.has("graph")&&!i.has("hybrid"))return[];const s=new Map,m=(e,c,f)=>{const $=e.toLowerCase();if(x.has($))return;const H=s.get($)||{name:e,weight:0,from:f};H.weight+=c,s.set($,H)},w=g?[g]:[],x=new Set(h.notNames),p=new Set(C.filter(e=>e.echo).map(e=>e.id));for(const e of M(o,{exclude:w}))m(e,2,"question");P.slice(0,3).forEach((e,c)=>M(e.snippet,{exclude:w}).forEach(f=>m(f,1.5/(1+c),"memory"))),C.filter(e=>!e.echo).slice(0,8).forEach((e,c)=>[...e.names||[],...M(`${e.title}
4
- ${e.snippet||""}`,{midSentence:!0,exclude:w})].forEach(f=>m(f,1/(2+c),e.id)));const y=e=>C.slice(0,8).filter(c=>`${c.title} ${c.snippet||""} ${(c.names||[]).join(" ")}`.toLowerCase().includes(e)).length,z=Math.min(8,C.length),Y=[...s.values()].some(e=>e.from==="question"||e.from==="memory"),_=[...s.entries()].filter(([e,c])=>c.from==="question"||c.from==="memory"||(!Y||y(e)>=2)&&(z<4||y(e)<=z/2)).map(([e,c])=>({...c,key:e,weight:c.weight/(1+Math.max(0,y(e)-2))})).sort((e,c)=>c.weight-e.weight).slice(0,S),L=new Map,D=(e,c,f)=>{const $=L.get(e.id)||{...e,score:0,via:[]};$.score+=c,f&&!$.via.includes(f)&&$.via.push(f),L.set(e.id,$)};C.forEach((e,c)=>D(e,(e.echo?.05:.5)/(1+c),null));for(const e of _)(await R({terms:[e.name.toLowerCase()],phrase:!0,kind:O,sinceAt:q(A),limit:10})||[]).filter(f=>f.id!==k&&!p.has(f.id)&&!B(o,`${f.title}
5
- ${f.snippet||""}`)).forEach((f,$)=>D(f,e.weight/(1+$),e.name));return u.plan.names=_.map(e=>e.name),[...L.values()].sort((e,c)=>c.score-e.score).slice(0,l).map(e=>({...e,via:e.via.length?e.via.join(", "):void 0}))}),await E("hybrid",async()=>{if(!i.has("hybrid"))return[];const s=(u.modes.graph||[]).filter(p=>p.via),m=[u.modes.memory,u.modes.keyword,s].map(p=>(p||[]).map(y=>y.id)),w=new Map;for(const p of["graph","keyword","memory"])for(const y of u.modes[p]||[])w.has(y.id)||w.set(y.id,{...y,from:[]});for(const p of["memory","keyword","graph"])for(const y of u.modes[p]||[])w.get(y.id)?.from.push(p);const x=F(m,{limit:l+5}).map(({id:p,score:y})=>({...w.get(p),score:y,from:w.get(p).from.join("+")}));return[...x.filter(p=>!p.echo),...x.filter(p=>p.echo)].slice(0,l)}),n&&i.has("hybrid")&&await E("reranked",async()=>{const s=await G(o,u.modes.hybrid||[],{decide:n});return u.decision=s.decision,s.reranked});for(const s of Z)i.has(s)||delete u.modes[s];return i.has("keyword")&&(u.modes.keyword=C.slice(0,l)),u}const J=[/\bmy\s+(?:friends?|family|wife|husband|partner|mom|mum|dad|mother|father|son|daughter|kids?|brother|sister|boss|manager|colleagues?|team|doctor|neighbou?rs?|contacts?|notes?|meetings?|chats?|trip|plans?|tasks?|reminders?|flight|hotel|appointment|address|car|house|home)\b/i,/\b(?:did|have|had)\s+(?:i|we)\b/i,/\bwhat\s+did\s+(?:i|we|\w+)\s+(?:say|decide|agree|discuss|mention|write|note)\b/i,/\b(?:when|where|who|what)\s+(?:was|were|is|are)\s+(?:my|our)\b/i,/\b(?:i|we)\s+(?:told you|mentioned|said|talked about|discussed)\b/i,/\bremind me\b/i,/\bwho\s+(?:do|did|have)\s+i\s+(?:meet|met|talk|speak|spoke|chat)/i,/\b(?:meetings?|calls?|chats?|notes?)\s+(?:per|by|each|every|a)\s+(?:month|week|day)\b/i],K=/^\s*(?:(?:ok(?:ay)?|hey|so|and|also|please)[\s,]+)*(?:remember|note|keep in mind|don'?t forget|never forget|forget|call me|save (?:that|this))\b/i;function ne(o,{names:a=[]}={}){const n=String(o||"");if(n.trim().length<6||K.test(n))return!1;if(J.some(t=>t.test(n))||/\b(meetings?|calls?|chats?|notes?|conversations?)\b/i.test(n)&&M(n).length)return!0;const r=n.toLowerCase();return a.some(t=>t&&new RegExp(`\\b${String(t).toLowerCase().replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\b`).test(r))}function oe(o,{max:a=5,now:n=Date.now()}={}){const r=(o?.modes?.reranked||o?.modes?.hybrid||[]).filter(d=>!d.echo).slice(0,a);if(!r.length)return null;const t=r.map((d,l)=>{const v=d.kind==="memory"?"memory":`${d.id}${d.title?` “${String(d.title).slice(0,80)}”`:""}`,S=String(d.snippet||d.title||"").replace(/\s+/g," ").trim().slice(0,300);return`${l+1}. [${v}] ${S}`}),g=o?.decision?.verdict==="found"?`
1
+ import{fuseRRF as F}from"./rrf.js";import{lexicalPlan as T}from"./recall.js";import{recall as Q}from"./memory.js";const Z=Object.freeze(["memory","keyword","graph","hybrid"]),W=new Set("i im ive id ill the a an this that these those what who whom whose which when where why how is are was were do does did can could will would should my your our their his her its we you he she they it me him them us yes no ok okay hi hello hey thanks please sure also and but or so if then monday tuesday wednesday thursday friday saturday sunday january february march april may june july august september october november december today tomorrow yesterday chap chapel chatpanel gemini nano claude codex speaker note notes chat chats meeting meetings summary topics action items met meet saw see called call asked ask told tell emailed email texted text messaged pinged ping spoke talked thanks thank dear cc per via with from here there now sorry great sure maybe perhaps still just only even also yet here's there's let please".split(/\s+/));function M(o,{max:a=12,midSentence:n=!1,exclude:r=[]}={}){const t=new Map,y=new Set(r.map(l=>String(l).toLowerCase()).filter(Boolean)),k=/\b([A-Z][a-z][A-Za-z'-]+(?:\s+[A-Z][a-z][A-Za-z'-]+){0,2})\b/g,d=String(o||"");for(const l of d.matchAll(k)){if(n&&/(^|[.!?:|\n"“]\s*)$/.test(d.slice(Math.max(0,l.index-3),l.index)))continue;const v=l[1].split(/\s+/).filter(i=>!W.has(i.toLowerCase().replace(/'s$/,"")));if(!v.length)continue;const S=v.join(" ").replace(/'s$/,"");if(S.length<3)continue;const b=S.toLowerCase();if(![...y].some(i=>b===i||b.split(" ").some(h=>i.split(" ").includes(h)))&&(t.set(b,t.get(b)||{name:S,count:0}),t.get(b).count+=1,t.size>=a*2))break}return[...t.values()].sort((l,v)=>v.count-l.count).slice(0,a).map(l=>l.name)}function I(o,{plan:a=null}={}){const n=(a?.terms?.length?a.terms:T(o).terms).map(t=>String(t).toLowerCase().replace(/[^a-z0-9]/g,"")).filter(t=>t.length>=2),r=new Set(n);for(const t of n)t.length>=7&&r.add(t.slice(0,5));return[...r].slice(0,12)}const q=o=>o?.sinceAt||0;function B(o,a){const n=I(o).filter(t=>t.length>=4);if(n.length<2)return!1;const r=String(a||"").toLowerCase();return n.filter(t=>r.includes(t)).length/n.length>=.8}const X=500;function N(o){const a=(n,r)=>[...new Set((Array.isArray(n)?n:[]).map(r).filter(Boolean))].slice(-X);return{notNames:a(o?.notNames,n=>String(n||"").replace(/\s+/g," ").trim().toLowerCase().slice(0,80)),hidden:a(o?.hidden,n=>String(n||"").trim().slice(0,200))}}function te(o,{op:a,value:n}){const r=N(o),t=String(n||"").trim();return t?a==="not-a-name"?N({...r,notNames:[...r.notNames,t]}):a==="undo-name"?{...r,notNames:r.notNames.filter(y=>y!==t.toLowerCase())}:a==="hide"?N({...r,hidden:[...r.hidden,t]}):a==="unhide"?{...r,hidden:r.hidden.filter(y=>y!==t)}:r:r}async function G(o,a,{decide:n,k:r=6}={}){const t=a.slice(0,r);if(!n||!t.length)return{reranked:a,decision:{verdict:"unknown"}};const y=[`Question: ${String(o).slice(0,400)}`,"",...t.map((i,h)=>`[${h+1}] ${i.title}: ${String(i.snippet||"").replace(/\s+/g," ").slice(0,280)}`)].join(`
2
+ `),k={};t.forEach((i,h)=>{k[`p${h+1}`]={type:"score",instructions:`How well does passage [${h+1}] answer the question? A passage that only repeats the question, or says it cannot tell, does NOT answer it.`,options:["no","partly","answers it"]}}),k.answer={type:"choice",instructions:'Which passage gives the answer itself (a name, a fact, a date)? "none" if none does.',options:[...t.map((i,h)=>String(h+1)),"none"]};let d=null;try{d=await n({state:y,questions:k})}catch{d=null}const l=d?.answers;if(!l)return{reranked:a,decision:{verdict:"unknown"}};const v=t.map((i,h)=>({...i,relevance:Number(l[`p${h+1}`]?.value??0),at:h})).sort((i,h)=>h.relevance-i.relevance||i.at-h.at).map(({at:i,...h})=>h),S=String(l.answer?.value??"none"),b=S==="none"?null:t[Number(S)-1];return{reranked:[...v,...a.slice(r)],decision:b?{verdict:"found",id:b.id,title:b.title,by:d.model||"model",calibrated:d.calibrated!==!1}:{verdict:"not-found",by:d.model||"model",calibrated:d.calibrated!==!1}}}async function se(o,{lexical:a,decide:n=null,corrections:r=null,memories:t=[],self:y="",excludeId:k=null,plan:d=null,limit:l=10,modes:v=Z,hops:S=5,now:b=()=>Date.now()}={}){const i=new Set(v),h=N(r),j=new Set(h.hidden),R=async s=>(await a(s)||[]).filter(m=>!j.has(m.id)),A=d||T(o),O={chats:"chat",notes:"note",meetings:"meeting"}[A.scope]||"",u={plan:{terms:I(o,{plan:A}),scope:A.scope,since:A.since||""},modes:{},ms:{},errors:{}},E=async(s,m)=>{const w=b();try{u.modes[s]=await m()}catch(x){u.modes[s]=[],u.errors[s]=String(x?.message||x)}return u.ms[s]=b()-w,u.modes[s]},P=await E("memory",async()=>i.has("memory")||i.has("graph")||i.has("hybrid")?Q(t,{text:o,includeAmbient:!1,limit:l}).map((s,m)=>({id:`memory:${s.id}`,kind:"memory",title:s.text,date:s.updatedAt||0,snippet:s.text,score:1/(1+m)})).filter(s=>!j.has(s.id)):[]),C=await E("keyword",async()=>i.has("keyword")||i.has("graph")||i.has("hybrid")?(await R({terms:u.plan.terms,kind:O,sinceAt:q(A),limit:Math.max(l,20)+5})||[]).filter(s=>s.id!==k).map((s,m)=>({...s,echo:B(o,`${s.title}
3
+ ${s.snippet||""}`),rank:m})).sort((s,m)=>Number(s.echo)-Number(m.echo)||s.rank-m.rank).map(({rank:s,...m},w)=>({...m,score:1/(1+w),...m.echo?{via:"an earlier time you asked"}:{}})):[]);await E("graph",async()=>{if(!i.has("graph")&&!i.has("hybrid"))return[];const s=new Map,m=(e,c,f)=>{const $=e.toLowerCase();if(x.has($))return;const H=s.get($)||{name:e,weight:0,from:f};H.weight+=c,s.set($,H)},w=y?[y]:[],x=new Set(h.notNames),p=new Set(C.filter(e=>e.echo).map(e=>e.id));for(const e of M(o,{exclude:w}))m(e,2,"question");P.slice(0,3).forEach((e,c)=>M(e.snippet,{exclude:w}).forEach(f=>m(f,1.5/(1+c),"memory"))),C.filter(e=>!e.echo).slice(0,8).forEach((e,c)=>[...e.names||[],...M(`${e.title}
4
+ ${e.snippet||""}`,{midSentence:!0,exclude:w})].forEach(f=>m(f,1/(2+c),e.id)));const g=e=>C.slice(0,8).filter(c=>`${c.title} ${c.snippet||""} ${(c.names||[]).join(" ")}`.toLowerCase().includes(e)).length,z=Math.min(8,C.length),Y=[...s.values()].some(e=>e.from==="question"||e.from==="memory"),_=[...s.entries()].filter(([e,c])=>c.from==="question"||c.from==="memory"||(!Y||g(e)>=2)&&(z<4||g(e)<=z/2)).map(([e,c])=>({...c,key:e,weight:c.weight/(1+Math.max(0,g(e)-2))})).sort((e,c)=>c.weight-e.weight).slice(0,S),L=new Map,D=(e,c,f)=>{const $=L.get(e.id)||{...e,score:0,via:[]};$.score+=c,f&&!$.via.includes(f)&&$.via.push(f),L.set(e.id,$)};C.forEach((e,c)=>D(e,(e.echo?.05:.5)/(1+c),null));for(const e of _)(await R({terms:[e.name.toLowerCase()],phrase:!0,kind:O,sinceAt:q(A),limit:10})||[]).filter(f=>f.id!==k&&!p.has(f.id)&&!B(o,`${f.title}
5
+ ${f.snippet||""}`)).forEach((f,$)=>D(f,e.weight/(1+$),e.name));return u.plan.names=_.map(e=>e.name),[...L.values()].sort((e,c)=>c.score-e.score).slice(0,l).map(e=>({...e,via:e.via.length?e.via.join(", "):void 0}))}),await E("hybrid",async()=>{if(!i.has("hybrid"))return[];const s=(u.modes.graph||[]).filter(p=>p.via),m=[u.modes.memory,u.modes.keyword,s].map(p=>(p||[]).map(g=>g.id)),w=new Map;for(const p of["graph","keyword","memory"])for(const g of u.modes[p]||[])w.has(g.id)||w.set(g.id,{...g,from:[]});for(const p of["memory","keyword","graph"])for(const g of u.modes[p]||[])w.get(g.id)?.from.push(p);const x=F(m,{limit:l+5}).map(({id:p,score:g})=>({...w.get(p),score:g,from:w.get(p).from.join("+")}));return[...x.filter(p=>!p.echo),...x.filter(p=>p.echo)].slice(0,l)}),n&&i.has("hybrid")&&await E("reranked",async()=>{const s=await G(o,u.modes.hybrid||[],{decide:n});return u.decision=s.decision,s.reranked});for(const s of Z)i.has(s)||delete u.modes[s];return i.has("keyword")&&(u.modes.keyword=C.slice(0,l)),u}const J=[/\bmy\s+(?:friends?|family|wife|husband|partner|mom|mum|dad|mother|father|son|daughter|kids?|brother|sister|boss|manager|colleagues?|team|doctor|neighbou?rs?|contacts?|notes?|meetings?|chats?|trip|plans?|tasks?|reminders?|flight|hotel|appointment|address|car|house|home)\b/i,/\b(?:did|have|had)\s+(?:i|we)\b/i,/\bwhat\s+did\s+(?:i|we|\w+)\s+(?:say|decide|agree|discuss|mention|write|note)\b/i,/\b(?:when|where|who|what)\s+(?:was|were|is|are)\s+(?:my|our)\b/i,/\b(?:i|we)\s+(?:told you|mentioned|said|talked about|discussed)\b/i,/\bremind me\b/i,/\b(?:was|were|am|are)\s+(?:i|we)\s+(?:planning|going|supposed|meant|thinking|hoping|booked|scheduled)\b/i,/\b(?:i|we)\s+(?:was|were)\s+(?:planning|going to|supposed to|meant to|thinking of|hoping to)\b/i,/\b(?:i|we)\s+(?:planned|booked|scheduled|decided)\b/i,/\bwho\s+(?:do|did|have)\s+i\s+(?:meet|met|talk|speak|spoke|chat)/i,/\b(?:meetings?|calls?|chats?|notes?)\s+(?:per|by|each|every|a)\s+(?:month|week|day)\b/i],K=/^\s*(?:(?:ok(?:ay)?|hey|so|and|also|please)[\s,]+)*(?:remember|note|keep in mind|don'?t forget|never forget|forget|call me|save (?:that|this))\b/i;function ne(o,{names:a=[]}={}){const n=String(o||"");if(n.trim().length<6||K.test(n))return!1;if(J.some(t=>t.test(n))||/\b(meetings?|calls?|chats?|notes?|conversations?)\b/i.test(n)&&M(n).length)return!0;const r=n.toLowerCase();return a.some(t=>t&&new RegExp(`\\b${String(t).toLowerCase().replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\b`).test(r))}function oe(o,{max:a=5,now:n=Date.now()}={}){const r=(o?.modes?.reranked||o?.modes?.hybrid||[]).filter(d=>!d.echo).slice(0,a);if(!r.length)return null;const t=r.map((d,l)=>{const v=d.kind==="memory"?"memory":`${d.id}${d.title?` “${String(d.title).slice(0,80)}”`:""}`,S=String(d.snippet||d.title||"").replace(/\s+/g," ").trim().slice(0,300);return`${l+1}. [${v}] ${S}`}),y=o?.decision?.verdict==="found"?`
6
6
  Most likely answered by: ${o.decision.title}`:"",k=`(ALREADY SEARCHED the person's own chats, notes, meetings and memory for the question below. Answer from this; cite the [id] you used. If the answer is not here, say you could not find it in their data — never guess, and never say you have no access to their data.)
7
7
 
8
8
  ${t.join(`
9
- `)}${g}`;return{id:`prefetch_personal_${n}`,kind:"prefetch",prefetch:"personal",title:"Searched your own data",text:k,chars:k.length}}export{X as MAX_CORRECTIONS,Z as SEARCH_MODES,te as correct,oe as evidenceAttachment,B as isEcho,I as keywordTerms,M as namesIn,N as normalizeCorrections,ne as personalAsk,G as rerankAndDecide,se as runSearchModes};
9
+ `)}${y}`;return{id:`prefetch_personal_${n}`,kind:"prefetch",prefetch:"personal",title:"Searched your own data",text:k,chars:k.length}}export{X as MAX_CORRECTIONS,Z as SEARCH_MODES,te as correct,oe as evidenceAttachment,B as isEcho,I as keywordTerms,M as namesIn,N as normalizeCorrections,ne as personalAsk,G as rerankAndDecide,se as runSearchModes};
@@ -0,0 +1 @@
1
+ const c=15e3,h=Object.freeze({CHATPANEL_SERVICE:"1"});function p(e={},{labels:s=["net.chatpanel.gateway","net.chatpanel.bridge"]}={}){return e.CHATPANEL_MANAGED_BY==="desktop"?"desktop":e.XPC_SERVICE_NAME&&s.includes(e.XPC_SERVICE_NAME)?"launchd":e.CHATPANEL_SERVICE==="1"?"service":null}function u({name:e,self:s,holder:n,managedBy:i,port:t}){const o=e==="bridge"?"Bridge":"Gateway";if(n?.ours&&i){const r=a(s,n.version);return{action:"standby",lines:[`ChatPanel ${o} v${n.version||"?"} already answers on ${t}; this copy (v${s}, started by ${i}) is standing by and takes over the moment the port is free.`,...r>0?[`This copy is newer. To switch now, stop the other one (\`chatpanel-${e} --status\` shows where it runs).`]:[]]}}if(n?.ours){const r=a(s,n.version);return{action:"exit",lines:[`ChatPanel ${o} v${n.version||"?"} is already running on ${t} — this one (v${s}) did not start.`,r>0?`To replace it with this version and keep it starting at login: chatpanel-${e} --install`:r<0?`The running one is NEWER. Nothing to do — this copy (v${s}) is the stale one; \`which -a chatpanel-${e}\` shows where it comes from.`:`It is this same version: nothing to do. \`chatpanel-${e} --status\` shows how it is started.`]}}return{action:"exit",lines:[]}}function a(e,s){const n=String(e||"").split(".").map(t=>parseInt(t,10)),i=String(s||"").split(".").map(t=>parseInt(t,10));if(n.length<3||i.length<3||n.some(Number.isNaN)||i.some(Number.isNaN))return 0;for(let t=0;t<3;t+=1)if(n[t]!==i[t])return n[t]>i[t]?1:-1;return 0}export{h as SERVICE_ENV,c as STANDBY_POLL_MS,a as compareVersions,u as portClashPlan,p as serviceManagerOf};