@chatpanel/events 0.114.1 → 0.115.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/events",
3
- "version": "0.114.1",
3
+ "version": "0.115.0",
4
4
  "description": "The canonical ChatPanel event-log and capability contracts — typed durable facts, clock-free deterministic linearization, schema upcasting, and the invariants the replay harness asserts. Pure, dependency-free ESM shared by the ChatPanel extension, gateway and bridge.",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/presence.js CHANGED
@@ -1,3 +1,3 @@
1
- import{approxTokens as g}from"./sources-retrieval.js";const w=350,O=60,u=6;function K(e,t=[]){const n=new Set;for(const i of e?.specs||[]){const o=i?.name||i?.function?.name;if(!o)continue;n.add(o);const a=(i.parameters||i.function?.parameters||i.input_schema||null)?.properties?.action?.enum;if(Array.isArray(a))for(const c of a)typeof c=="string"&&n.add(`${o}:${c}`)}for(const i of t||[])i&&n.add(String(i));return n}function m(e,t=O){const n=String(e||"").replace(/\s+/g," ").trim();return n.length>t?n.slice(0,t-1).trimEnd()+"…":n}function p(e){const t=Math.max(0,Math.floor(Number(e)||0));return t<20?String(t):`${Math.floor(t/10)*10}+`}function T(e){const t=Math.max(0,Math.floor((Number(e)||0)/6e4));return t<10?`${t} min`:`~${Math.floor(t/5)*5} min`}function D(e){const t=Math.max(0,Math.floor((Number(e)||0)/6e4));return t<1?"just now":t<10?`${t} min ago`:`~${Math.floor(t/5)*5} min ago`}function A(e){try{return new URL(e).hostname.replace(/^www\./,"")}catch{return""}}function x(e){const t=new Date(Number(e)||0);return Number.isFinite(t.getTime())&&t.getTime()>0?t.toISOString().slice(0,10):""}const _=[{kind:"meeting",priority:1,via:["find:meeting_live_transcript","meeting_live_transcript"],applies:e=>!!e.meeting,key:e=>`${e.meeting.id||""}|${m(e.meeting.title)}|${e.meeting.platform||""}`,render:(e,t)=>{const n=e.meeting,i=[];return n.platform&&i.push(String(n.platform)),n.startedAt&&i.push(`${T(t-n.startedAt)} in`),Number(n.segments)>0&&i.push(`${p(n.segments)} captions`),n.lastCaptionAt&&i.push(`last ${D(t-n.lastCaptionAt)}`),n.hasSummary&&i.push("running summary kept"),`Live meeting: "${m(n.title||"Meeting")}"${i.length?` (${i.join(", ")})`:""} — read with find {"action":"meeting_live_transcript"} (args.sinceMinutes for the recent part). Not included here.`}},{kind:"page",priority:2,via:["page:read_page","read_page"],applies:e=>!!e.page&&(e.page.title||e.page.url),key:e=>`${A(e.page.url)}|${m(e.page.title)}`,render:e=>{const t=e.page,n=A(t.url);return`Active tab: "${m(t.title||n||"page")}"${n?` (${n})`:""} — read with page {"action":"read_page"} (args.query on a long page). Not included here.`}},{kind:"fetched",priority:3,via:["source"],applies:e=>Array.isArray(e.fetched)&&e.fetched.length>0,key:e=>e.fetched.map(t=>t.id).join(","),render:e=>`Already fetched in this conversation: ${e.fetched.slice(0,u).map(n=>`${n.id} ${m(n.title,40)} (${n.agoText||"earlier"})`).join("; ")} — read one with source {"id":"<id>"} (args.query for a part); do not fetch the same thing again.`},{kind:"sidelines",priority:3,via:["find:history_search","find","history_search"],applies:e=>Array.isArray(e.sidelines)&&e.sidelines.length>0,key:e=>e.sidelines.map(t=>`${t.index}:${t.folded?"f":"o"}`).join(","),render:e=>{const t=e.sidelines.slice(0,u).map(i=>{const o=i.folded?"folded back":"open";return`#${i.index||"?"} "${m(i.title||"sideline",40)}" (${o})`}),n=e.sidelines.length>u?`, +${e.sidelines.length-u} more`:"";return`Sidelines of this thread: ${t.join("; ")}${n} — a sideline is a chat; find {"action":"history_search"} reads one.`}},{kind:"teams",priority:4,via:["team"],applies:e=>Array.isArray(e.teams)&&e.teams.length>0,key:e=>e.teams.map(t=>typeof t=="string"?t:t?.name).filter(Boolean).join(","),render:e=>{const t=e.teams.map(o=>typeof o=="string"?o:o?.name).filter(Boolean),n=t.slice(0,u).join(", "),i=t.length>u?`, +${t.length-u} more`:"";return`Teams & agents you can run: ${n}${i} — team {"action":"run","name":…}; {"action":"describe"} for how.`}},{kind:"notes",priority:5,via:["find:history_search","find","history_search"],applies:e=>e.notes&&Number(e.notes.count)>0,key:e=>p(e.notes.count),render:e=>{const t=(e.notes.recent||[]).slice(0,3).map(n=>`"${m(typeof n=="string"?n:n?.title,40)}"`).filter(n=>n!=='""');return`Notes: ${p(e.notes.count)}${t.length?` (recent: ${t.join(", ")})`:""} — find {"action":"history_search","args":{"query":…}} searches them.`}},{kind:"meetings",priority:6,via:["find:history_list_meetings","history_list_meetings"],applies:e=>e.meetings&&Number(e.meetings.count)>0,key:e=>`${p(e.meetings.count)}|${m(e.meetings.latest?.title,40)}`,render:e=>{const t=e.meetings.latest,n=t?` (latest: "${m(t.title,40)}"${x(t.date)?` ${x(t.date)}`:""})`:"";return`Past meetings: ${p(e.meetings.count)}${n} — find {"action":"history_list_meetings"}.`}},{kind:"skills",priority:7,via:["skill_open"],applies:e=>e.skills&&Number(e.skills.count)>0,key:e=>p(e.skills.count),render:e=>{const t=(e.skills.top||[]).slice(0,3).map(n=>typeof n=="string"?n:n?.name).filter(Boolean);return`Skills: ${p(e.skills.count)}${t.length?` (e.g. ${t.join(", ")})`:""} — skill_open {"name":…} loads one.`}},{kind:"memory",priority:8,via:["memory"],applies:e=>e.memory&&Number(e.memory.count)>0,key:e=>p(e.memory.count),render:e=>`Memory: ${p(e.memory.count)} durable facts about the user — memory {"action":"list"}.`},{kind:"chats",priority:9,via:["find:history_search","find","history_search"],applies:e=>e.chats&&Number(e.chats.count)>0,key:e=>p(e.chats.count),render:e=>`Past chats: ${p(e.chats.count)} — find {"action":"history_search","args":{"scope":"chats"}}.`}],P=Object.freeze(_.map(e=>e.kind)),S="Around this turn (NOT included — read what the question needs, one call):",N="Changed since your last turn:",B={meeting:"Live meeting ended — the transcript is now in past meetings.",page:"Active tab: none readable now.",sidelines:"Sidelines of this thread: none open now."};function v(e,t,n){const i=[],o=[];for(const r of _){if(!r.applies(e))continue;if(!r.via.some(c=>t.has(c))){o.push({kind:r.kind,why:"no reader armed"});continue}const a=`- ${r.render(e,n)}`;i.push({kind:r.kind,priority:r.priority,text:a,key:r.key(e),tokens:g(a)})}return{lines:i,omitted:o}}function E(e,t,n,i){let o=g(e)+t.reduce((a,c)=>a+c.tokens+1,0);const r=[...t];for(;o>n&&r.length>1;){let a=0;for(let l=1;l<r.length;l++)r[l].priority>r[a].priority&&(a=l);const[c]=r.splice(a,1);i.push({kind:c.kind,why:"over budget"}),o-=c.tokens+1}return r}const j=e=>e instanceof Set?e:new Set(Array.isArray(e)?e:[]);function C({facts:e={},reach:t=new Set,budget:n=w,now:i=Date.now()}={}){const{lines:o,omitted:r}=v(e||{},j(t),i);if(!o.length)return{text:"",lines:[],omitted:r,tokens:0,state:{}};const a=E(S,o,n,r),c=[S,...a.map(l=>l.text)].join(`
2
- `);return{text:c,lines:a.map(({kind:l,text:h,tokens:d})=>({kind:l,text:h,tokens:d})),omitted:r,tokens:g(c),state:Object.fromEntries(a.map(l=>[l.kind,l.key]))}}function R({facts:e={},reach:t=new Set,previous:n=null,budget:i=w,now:o=Date.now()}={}){const r=n&&typeof n=="object"?n:null;if(!r||!Object.keys(r).length)return C({facts:e,reach:t,budget:i,now:o});const{lines:a,omitted:c}=v(e||{},j(t),o),l=new Map(a.map(s=>[s.kind,s])),h=a.filter(s=>r[s.kind]!==s.key),d=[];for(const s of Object.keys(r)){if(l.has(s))continue;const f=_.find($=>$.kind===s);d.push({kind:s,priority:f?f.priority:99,text:`- ${B[s]||`${s}: no longer available.`}`,tokens:0}),d[d.length-1].tokens=g(d[d.length-1].text)}const y=Object.fromEntries(a.map(s=>[s.kind,s.key]));if(!h.length&&!d.length)return{text:"",lines:[],omitted:c,tokens:0,state:y,unchanged:!0};const k=E(N,[...h,...d],i,c),b=[N,...k.map(s=>s.text)].join(`
3
- `),M=new Set(k.map(s=>s.kind));for(const s of h)!M.has(s.kind)&&r[s.kind]!=null&&(y[s.kind]=r[s.kind]);return{text:b,lines:k.map(({kind:s,text:f,tokens:$})=>({kind:s,text:f,tokens:$})),omitted:c,tokens:g(b),state:y,unchanged:!1}}function q(e,t){const n=String(t||"").trim(),i=Array.isArray(e)?e:[];if(!n)return i;let o=-1;for(let r=i.length-1;r>=0;r--)if(i[r]?.role==="user"){o=r;break}return o<0?i:i.map((r,a)=>a===o?{...r,presence:n}:r)}import{presenceBlock as G}from"./context-attachments.js";export{w as PRESENCE_BUDGET_TOKENS,P as PRESENCE_KINDS,G as presenceBlock,R as presenceDelta,C as presenceFor,K as reachOf,p as roundCount,T as roundMinutes,q as withPresence};
1
+ import{approxTokens as g}from"./sources-retrieval.js";const w=350,O=60,u=6;function q(e,t=[]){const n=new Set;for(const i of e?.specs||[]){const o=i?.name||i?.function?.name;if(!o)continue;n.add(o);const a=(i.parameters||i.function?.parameters||i.input_schema||null)?.properties?.action?.enum;if(Array.isArray(a))for(const c of a)typeof c=="string"&&n.add(`${o}:${c}`)}for(const i of t||[])i&&n.add(String(i));return n}function m(e,t=O){const n=String(e||"").replace(/\s+/g," ").trim();return n.length>t?n.slice(0,t-1).trimEnd()+"…":n}function d(e){const t=Math.max(0,Math.floor(Number(e)||0));return t<20?String(t):`${Math.floor(t/10)*10}+`}function T(e){const t=Math.max(0,Math.floor((Number(e)||0)/6e4));return t<10?`${t} min`:`~${Math.floor(t/5)*5} min`}function D(e){const t=Math.max(0,Math.floor((Number(e)||0)/6e4));return t<1?"just now":t<10?`${t} min ago`:`~${Math.floor(t/5)*5} min ago`}function A(e){try{return new URL(e).hostname.replace(/^www\./,"")}catch{return""}}function x(e){const t=new Date(Number(e)||0);return Number.isFinite(t.getTime())&&t.getTime()>0?t.toISOString().slice(0,10):""}const _=[{kind:"meeting",priority:1,via:["find:meeting_live_transcript","meeting_live_transcript"],applies:e=>!!e.meeting,key:e=>`${e.meeting.id||""}|${m(e.meeting.title)}|${e.meeting.platform||""}`,render:(e,t)=>{const n=e.meeting,i=[];return n.platform&&i.push(String(n.platform)),n.startedAt&&i.push(`${T(t-n.startedAt)} in`),Number(n.segments)>0&&i.push(`${d(n.segments)} captions`),n.lastCaptionAt&&i.push(`last ${D(t-n.lastCaptionAt)}`),n.hasSummary&&i.push("running summary kept"),`Live meeting: "${m(n.title||"Meeting")}"${i.length?` (${i.join(", ")})`:""} — read with find {"action":"meeting_live_transcript"} (args.sinceMinutes for the recent part). Not included here.`}},{kind:"page",priority:2,via:["page:read_page","read_page"],applies:e=>!!e.page&&(e.page.title||e.page.url),key:e=>`${A(e.page.url)}|${m(e.page.title)}`,render:e=>{const t=e.page,n=A(t.url);return`Active tab: "${m(t.title||n||"page")}"${n?` (${n})`:""} — read with page {"action":"read_page"} (args.query on a long page). Not included here. A question about something this conversation has not mentioned ("it", "this", a name, a headline) is most likely about this tab: read it before searching history or the web.`}},{kind:"fetched",priority:3,via:["source"],applies:e=>Array.isArray(e.fetched)&&e.fetched.length>0,key:e=>e.fetched.map(t=>t.id).join(","),render:e=>`Already fetched in this conversation: ${e.fetched.slice(0,u).map(n=>`${n.id} ${m(n.title,40)} (${n.agoText||"earlier"})`).join("; ")} — read one with source {"id":"<id>"} (args.query for a part); do not fetch the same thing again.`},{kind:"sidelines",priority:3,via:["find:history_search","find","history_search"],applies:e=>Array.isArray(e.sidelines)&&e.sidelines.length>0,key:e=>e.sidelines.map(t=>`${t.index}:${t.folded?"f":"o"}`).join(","),render:e=>{const t=e.sidelines.slice(0,u).map(i=>{const o=i.folded?"folded back":"open";return`#${i.index||"?"} "${m(i.title||"sideline",40)}" (${o})`}),n=e.sidelines.length>u?`, +${e.sidelines.length-u} more`:"";return`Sidelines of this thread: ${t.join("; ")}${n} — a sideline is a chat; find {"action":"history_search"} reads one.`}},{kind:"teams",priority:4,via:["team"],applies:e=>Array.isArray(e.teams)&&e.teams.length>0,key:e=>e.teams.map(t=>typeof t=="string"?t:t?.name).filter(Boolean).join(","),render:e=>{const t=e.teams.map(o=>typeof o=="string"?o:o?.name).filter(Boolean),n=t.slice(0,u).join(", "),i=t.length>u?`, +${t.length-u} more`:"";return`Teams & agents you can run: ${n}${i} — team {"action":"run","name":…}; {"action":"describe"} for how.`}},{kind:"notes",priority:5,via:["find:history_search","find","history_search"],applies:e=>e.notes&&Number(e.notes.count)>0,key:e=>d(e.notes.count),render:e=>{const t=(e.notes.recent||[]).slice(0,3).map(n=>`"${m(typeof n=="string"?n:n?.title,40)}"`).filter(n=>n!=='""');return`Notes: ${d(e.notes.count)}${t.length?` (recent: ${t.join(", ")})`:""} — find {"action":"history_search","args":{"query":…}} searches them.`}},{kind:"meetings",priority:6,via:["find:history_list_meetings","history_list_meetings"],applies:e=>e.meetings&&Number(e.meetings.count)>0,key:e=>`${d(e.meetings.count)}|${m(e.meetings.latest?.title,40)}`,render:e=>{const t=e.meetings.latest,n=t?` (latest: "${m(t.title,40)}"${x(t.date)?` ${x(t.date)}`:""})`:"";return`Past meetings: ${d(e.meetings.count)}${n} — find {"action":"history_list_meetings"}.`}},{kind:"skills",priority:7,via:["skill_open"],applies:e=>e.skills&&Number(e.skills.count)>0,key:e=>d(e.skills.count),render:e=>{const t=(e.skills.top||[]).slice(0,3).map(n=>typeof n=="string"?n:n?.name).filter(Boolean);return`Skills: ${d(e.skills.count)}${t.length?` (e.g. ${t.join(", ")})`:""} — skill_open {"name":…} loads one.`}},{kind:"memory",priority:8,via:["memory"],applies:e=>e.memory&&Number(e.memory.count)>0,key:e=>d(e.memory.count),render:e=>`Memory: ${d(e.memory.count)} durable facts about the user — memory {"action":"list"}.`},{kind:"chats",priority:9,via:["find:history_search","find","history_search"],applies:e=>e.chats&&Number(e.chats.count)>0,key:e=>d(e.chats.count),render:e=>`Past chats: ${d(e.chats.count)} — find {"action":"history_search","args":{"scope":"chats"}}.`}],K=Object.freeze(_.map(e=>e.kind)),S="Around this turn (NOT included — read what the question needs, one call):",v="Changed since your last turn:",B={meeting:"Live meeting ended — the transcript is now in past meetings.",page:"Active tab: none readable now.",sidelines:"Sidelines of this thread: none open now."};function N(e,t,n){const i=[],o=[];for(const r of _){if(!r.applies(e))continue;if(!r.via.some(c=>t.has(c))){o.push({kind:r.kind,why:"no reader armed"});continue}const a=`- ${r.render(e,n)}`;i.push({kind:r.kind,priority:r.priority,text:a,key:r.key(e),tokens:g(a)})}return{lines:i,omitted:o}}function E(e,t,n,i){let o=g(e)+t.reduce((a,c)=>a+c.tokens+1,0);const r=[...t];for(;o>n&&r.length>1;){let a=0;for(let l=1;l<r.length;l++)r[l].priority>r[a].priority&&(a=l);const[c]=r.splice(a,1);i.push({kind:c.kind,why:"over budget"}),o-=c.tokens+1}return r}const j=e=>e instanceof Set?e:new Set(Array.isArray(e)?e:[]);function C({facts:e={},reach:t=new Set,budget:n=w,now:i=Date.now()}={}){const{lines:o,omitted:r}=N(e||{},j(t),i);if(!o.length)return{text:"",lines:[],omitted:r,tokens:0,state:{}};const a=E(S,o,n,r),c=[S,...a.map(l=>l.text)].join(`
2
+ `);return{text:c,lines:a.map(({kind:l,text:h,tokens:p})=>({kind:l,text:h,tokens:p})),omitted:r,tokens:g(c),state:Object.fromEntries(a.map(l=>[l.kind,l.key]))}}function P({facts:e={},reach:t=new Set,previous:n=null,budget:i=w,now:o=Date.now()}={}){const r=n&&typeof n=="object"?n:null;if(!r||!Object.keys(r).length)return C({facts:e,reach:t,budget:i,now:o});const{lines:a,omitted:c}=N(e||{},j(t),o),l=new Map(a.map(s=>[s.kind,s])),h=a.filter(s=>r[s.kind]!==s.key),p=[];for(const s of Object.keys(r)){if(l.has(s))continue;const f=_.find($=>$.kind===s);p.push({kind:s,priority:f?f.priority:99,text:`- ${B[s]||`${s}: no longer available.`}`,tokens:0}),p[p.length-1].tokens=g(p[p.length-1].text)}const y=Object.fromEntries(a.map(s=>[s.kind,s.key]));if(!h.length&&!p.length)return{text:"",lines:[],omitted:c,tokens:0,state:y,unchanged:!0};const k=E(v,[...h,...p],i,c),b=[v,...k.map(s=>s.text)].join(`
3
+ `),M=new Set(k.map(s=>s.kind));for(const s of h)!M.has(s.kind)&&r[s.kind]!=null&&(y[s.kind]=r[s.kind]);return{text:b,lines:k.map(({kind:s,text:f,tokens:$})=>({kind:s,text:f,tokens:$})),omitted:c,tokens:g(b),state:y,unchanged:!1}}function R(e,t){const n=String(t||"").trim(),i=Array.isArray(e)?e:[];if(!n)return i;let o=-1;for(let r=i.length-1;r>=0;r--)if(i[r]?.role==="user"){o=r;break}return o<0?i:i.map((r,a)=>a===o?{...r,presence:n}:r)}import{presenceBlock as G}from"./context-attachments.js";export{w as PRESENCE_BUDGET_TOKENS,K as PRESENCE_KINDS,G as presenceBlock,P as presenceDelta,C as presenceFor,q as reachOf,d as roundCount,T as roundMinutes,R as withPresence};
package/tool-need.js CHANGED
@@ -1,3 +1,3 @@
1
- import{signalsFrom as k}from"./router.js";const v=new Set(["hi","hii","hiya","hey","heya","hello","helo","yo","sup","howdy","greetings","good","morning","afternoon","evening","night","day","thanks","thank","thankyou","thx","tnx","ty","cheers","appreciated","ok","okay","k","kk","got","sounds","perfect","great","cool","nice","awesome","lol","haha","hah","hehe","nvm","yep","yeah","yes","no","nope","sure","bye","goodbye","later","ya","cya","ciao","welcome","worries","problem","np","please","there","again","all","everyone","team","friend","mate","buddy","you","u","so","much","very","well","and","a","the"]),S=6;function x(t){const o=String(t||"").toLowerCase().replace(/[^\p{L}\s']/gu," ").split(/\s+/).filter(Boolean);return!o.length||o.length>S?!1:o.every(a=>v.has(a))}function A({request:t=null,signals:o=null,attachments:a=[],explicit:c=!1}={}){if(c)return{tools:!0,why:"the turn asked for tools"};if((a||[]).some(n=>n&&!n.auto))return{tools:!0,why:"the turn carries an attachment"};const h=String(t?.text??(t?.messages||[]).map(n=>n?.content||"").join(`
2
- `));return x(h)?(o||k(t||{})).smalltalk?{tools:!1,why:"a greeting — nothing to look up"}:{tools:!0,why:"the request may need something fetched"}:{tools:!0,why:"the request may need something fetched"}}const j=Object.freeze([["web",/\b(search|google|look ?up|latest|current|recent|today|this (week|month|year)|news|price|prices|pricing|cost of|quote|stock|market|website|url|online|web|docs?umentation|release notes|changelog|versions?)\b/i],["history",/\b(our (meeting|call|notes?|chats?|conversation)|what (did|was) (we|i)|we (decided|agreed|discussed|said)|in (my|our) (notes?|meetings?|history|chats?)|past (chats?|meetings?|notes?)|earlier (meeting|conversation|chat|note)|transcript|standup|retro)\b/i],["data",/\b(attached|attachment|this (page|document|file|pdf|spreadsheet|sheet)|the (document|file|pdf|spreadsheet) (above|provided|attached))\b/i]]);function _(t,{held:o=null}={}){const a=String(t||"");if(!a.trim())return[];const c=j.filter(([,e])=>e.test(a)).map(([e])=>e);if(!o)return c;const h=new Set((Array.isArray(o)?o:[]).map(e=>String(e).toLowerCase()));return c.filter(e=>h.has(e)||e==="history"&&h.has("data"))}const m=Object.freeze(["page","data","mcp","memory","note","team","sideline","skills","widgets","recipes"]),g=Object.freeze(["data","mcp","memory"]),b=/\b(this|the|current|open|active|that|my) (page|tab|site|website|article|post|thread|document|doc|file|pdf|sheet|spreadsheet|form|canvas|board|diagram|screen|window|video|table|cell|button|field|link|image)\b|\bon (the|this) (page|screen|tab)\b|\bhere\b|\bthis\b(?!\s+(morning|afternoon|evening|week|weekend|month|year|time|is (a|the|my))\b)|\bthese\b|\bthose\b/i,f=/\b(click|tap|press|type|fill|enter|select|scroll|drag|draw|paint|sketch|navigate|go to|open|close|submit|upload|download|play|pause|screenshot|inspect|read (the|this)|zoom|highlight|copy|paste|log ?in|sign ?in|sign ?up|checkout|add to cart|search (on|in) (the|this)|watch|browse)\b/i,L=/\b(build|make|create|write|generate|draft|code|design|implement|prototype)\b[^.?!]{0,40}\b(app|widget|tool|timer|calculator|tracker|checklist|game|dashboard|form|page|site|script|component|converter|counter|scoreboard|clock|note|dice)\b|\b(widget|app)\b/i,R=/\b(run|use|ask|start|save|create|make|set ?up|open|launch|kick ?off|assign|delegate)\b[^.?!]{0,30}\b(team|teams|agent|agents|skill|skills|recipe|recipes|sideline|project)\b|\b(the|my|our|this|that)\s+(\w+[\s-]+)?(team|agent|skill|recipe|sideline|project)\b|\bask (the|our|my) \w+ (to|for)\b|\b(executive|breakout|workflow)\b|remember this|save (this|that) as|^\s*\//i,w=/\b(summar\w*|analy\w*|review|edit|rewrite|fix|refactor|debug|translate|convert|extract|compare|explain (this|that|the)|proofread|format|organi[sz]e|plan)\b/i,E=300;function G({request:t=null,signals:o=null,attachments:a=[],explicit:c=!1,stable:h=!1}={}){const e=i=>({tools:!0,tier:"full",groups:new Set(m),why:i});if(h)return e("a warm process keeps one tool set");const n=A({request:t,signals:o,attachments:a,explicit:c});if(!n.tools)return{tools:!1,tier:"none",groups:new Set,why:n.why};if(c)return e(n.why);if((a||[]).some(i=>i&&!i.auto))return e("the turn carries an attachment");const s=String(t?.text??(t?.messages||[]).map(i=>i?.content||"").join(`
3
- `));if(!s.trim())return e("no text to read");if(s.length>E||/```/.test(s))return e("a long or code-bearing request");const u=b.test(s)||f.test(s)||w.test(s),d=R.test(s),p=L.test(s),y=w.test(s);if(!u&&!d&&!p)return{tools:!0,tier:"light",groups:new Set(g),why:"a lookup — the user's data and the web are enough"};const r=new Set(g),l=[];return u&&(r.add("page"),r.add("note"),l.push(f.test(s)?"the request asks to act":b.test(s)?"the request refers to the page or to something in view":"the request is work, not a lookup")),(y||d)&&r.add("skills"),d&&(r.add("team"),r.add("sideline"),r.add("recipes"),r.add("note"),l.push("the request names a team, skill, recipe or command")),p&&(r.add("widgets"),r.add("note"),l.push("the request asks to make something")),m.every(i=>r.has(i))?e(l.join("; ")):{tools:!0,tier:"task",groups:r,why:l.join("; ")}}export{G as equipmentFor,_ as grantsNeededFor,A as toolNeedFor};
1
+ import{signalsFrom as A}from"./router.js";const x=new Set(["hi","hii","hiya","hey","heya","hello","helo","yo","sup","howdy","greetings","good","morning","afternoon","evening","night","day","thanks","thank","thankyou","thx","tnx","ty","cheers","appreciated","ok","okay","k","kk","got","sounds","perfect","great","cool","nice","awesome","lol","haha","hah","hehe","nvm","yep","yeah","yes","no","nope","sure","bye","goodbye","later","ya","cya","ciao","welcome","worries","problem","np","please","there","again","all","everyone","team","friend","mate","buddy","you","u","so","much","very","well","and","a","the"]),R=6;function E(t){const o=String(t||"").toLowerCase().replace(/[^\p{L}\s']/gu," ").split(/\s+/).filter(Boolean);return!o.length||o.length>R?!1:o.every(i=>x.has(i))}function _({request:t=null,signals:o=null,attachments:i=[],explicit:c=!1}={}){if(c)return{tools:!0,why:"the turn asked for tools"};if((i||[]).some(a=>a&&!a.auto))return{tools:!0,why:"the turn carries an attachment"};const h=String(t?.text??(t?.messages||[]).map(a=>a?.content||"").join(`
2
+ `));return E(h)?(o||A(t||{})).smalltalk?{tools:!1,why:"a greeting — nothing to look up"}:{tools:!0,why:"the request may need something fetched"}:{tools:!0,why:"the request may need something fetched"}}const j=Object.freeze([["web",/\b(search|google|look ?up|latest|current|recent|today|this (week|month|year)|news|price|prices|pricing|cost of|quote|stock|market|website|url|online|web|docs?umentation|release notes|changelog|versions?)\b/i],["history",/\b(our (meeting|call|notes?|chats?|conversation)|what (did|was) (we|i)|we (decided|agreed|discussed|said)|in (my|our) (notes?|meetings?|history|chats?)|past (chats?|meetings?|notes?)|earlier (meeting|conversation|chat|note)|transcript|standup|retro)\b/i],["data",/\b(attached|attachment|this (page|document|file|pdf|spreadsheet|sheet)|the (document|file|pdf|spreadsheet) (above|provided|attached))\b/i]]);function q(t,{held:o=null}={}){const i=String(t||"");if(!i.trim())return[];const c=j.filter(([,s])=>s.test(i)).map(([s])=>s);if(!o)return c;const h=new Set((Array.isArray(o)?o:[]).map(s=>String(s).toLowerCase()));return c.filter(s=>h.has(s)||s==="history"&&h.has("data"))}const b=Object.freeze(["page","data","mcp","memory","note","team","sideline","skills","widgets","recipes"]),f=Object.freeze(["data","mcp","memory"]),w="page_read",y=/\b(this|the|current|open|active|that|my) (page|tab|site|website|article|post|thread|document|doc|file|pdf|sheet|spreadsheet|form|canvas|board|diagram|screen|window|video|table|cell|button|field|link|image)\b|\bon (the|this) (page|screen|tab)\b|\bhere\b|\bthis\b(?!\s+(morning|afternoon|evening|week|weekend|month|year|time|is (a|the|my))\b)|\bthese\b|\bthose\b/i,k=/\b(click|tap|press|type|fill|enter|select|scroll|drag|draw|paint|sketch|navigate|go to|open|close|submit|upload|download|play|pause|screenshot|inspect|read (the|this)|zoom|highlight|copy|paste|log ?in|sign ?in|sign ?up|checkout|add to cart|search (on|in) (the|this)|watch|browse)\b/i,L=/\b(build|make|create|write|generate|draft|code|design|implement|prototype)\b[^.?!]{0,40}\b(app|widget|tool|timer|calculator|tracker|checklist|game|dashboard|form|page|site|script|component|converter|counter|scoreboard|clock|note|dice)\b|\b(widget|app)\b/i,O=/\b(run|use|ask|start|save|create|make|set ?up|open|launch|kick ?off|assign|delegate)\b[^.?!]{0,30}\b(team|teams|agent|agents|skill|skills|recipe|recipes|sideline|project)\b|\b(the|my|our|this|that)\s+(\w+[\s-]+)?(team|agent|skill|recipe|sideline|project)\b|\bask (the|our|my) \w+ (to|for)\b|\b(executive|breakout|workflow)\b|remember this|save (this|that) as|^\s*\//i,v=/\b(summar\w*|analy\w*|review|edit|rewrite|fix|refactor|debug|translate|convert|extract|compare|explain (this|that|the)|proofread|format|organi[sz]e|plan)\b/i,G=300;function F({request:t=null,signals:o=null,attachments:i=[],explicit:c=!1,stable:h=!1,ambient:s=null}={}){const a=n=>({tools:!0,tier:"full",groups:new Set(b),why:n});if(h)return a("a warm process keeps one tool set");const d=_({request:t,signals:o,attachments:i,explicit:c});if(!d.tools)return{tools:!1,tier:"none",groups:new Set,why:d.why};if(c)return a(d.why);if((i||[]).some(n=>n&&!n.auto))return a("the turn carries an attachment");const r=String(t?.text??(t?.messages||[]).map(n=>n?.content||"").join(`
3
+ `));if(!r.trim())return a("no text to read");if(r.length>G||/```/.test(r))return a("a long or code-bearing request");const g=y.test(r)||k.test(r)||v.test(r),u=O.test(r),m=L.test(r),S=v.test(r),p=!!s?.page;if(!g&&!u&&!m){const n=new Set(f);return p&&n.add(w),{tools:!0,tier:"light",groups:n,why:p?"a lookup, asked from a readable tab — the user's data, the web, and a reader for the tab":"a lookup — the user's data and the web are enough"}}const e=new Set(f),l=[];return g&&(e.add("page"),e.add("note"),l.push(k.test(r)?"the request asks to act":y.test(r)?"the request refers to the page or to something in view":"the request is work, not a lookup")),(S||u)&&e.add("skills"),u&&(e.add("team"),e.add("sideline"),e.add("recipes"),e.add("note"),l.push("the request names a team, skill, recipe or command")),m&&(e.add("widgets"),e.add("note"),l.push("the request asks to make something")),p&&!e.has("page")&&e.add(w),b.every(n=>e.has(n))?a(l.join("; ")):{tools:!0,tier:"task",groups:e,why:l.join("; ")}}export{F as equipmentFor,q as grantsNeededFor,_ as toolNeedFor};