@chatpanel/events 0.295.0 → 0.332.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 (51) 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/capability-uses.js +1 -1
  8. package/client-prefs.js +1 -1
  9. package/clock.js +1 -0
  10. package/compaction.js +4 -4
  11. package/context-select.js +2 -0
  12. package/context-window.js +1 -1
  13. package/dialect-a2a.js +1 -1
  14. package/dialect-claude.js +1 -1
  15. package/digest.js +7 -0
  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/link-connect.js +1 -1
  23. package/link-protocol.js +1 -1
  24. package/link-routes.js +2 -0
  25. package/memory.js +2 -2
  26. package/model-candidates.js +1 -1
  27. package/note-tool.js +2 -2
  28. package/own-instructions.js +5 -0
  29. package/package.json +25 -1
  30. package/prefetch.js +4 -2
  31. package/provider-presets.js +1 -1
  32. package/research.js +7 -7
  33. package/retrieval-plan.js +1 -0
  34. package/sandbox-policy.js +1 -1
  35. package/search-modes.js +6 -6
  36. package/service-standby.js +1 -0
  37. package/settings-registry.js +1 -1
  38. package/stitch.js +16 -14
  39. package/thread-send.js +1 -0
  40. package/tool-group-data.js +1 -1
  41. package/tool-hints.js +4 -4
  42. package/tool-hub.js +9 -7
  43. package/tool-need.js +3 -3
  44. package/tool-result.js +2 -2
  45. package/turn-intent.js +3 -0
  46. package/turn-loop.js +4 -4
  47. package/vault.js +1 -1
  48. package/voice-intents.js +2 -2
  49. package/voice-sample.js +1 -1
  50. package/weather-tool.js +10 -1
  51. package/weather.js +2 -2
@@ -1 +1 @@
1
- import{agentTrust as v,engineOf as x}from"./agent.js";import{describeEngine as C,engineRef as A}from"./engine.js";import{harnessCard as u,harnessEgress as I}from"./harness-cards.js";import{agentColor as R,agentInitials as $,agentKind as E,cardNumbers as N,GRANT_INFO as p}from"./team-org.js";const c=Object.freeze({"built-in":["built-in","shipped with ChatPanel and reviewed by us"],user:["yours","you wrote this one here"],community:["from a folder","it arrived in a directory on this machine — we cannot tell who wrote it"]}),O=Object.freeze({chatpanel:"ChatPanel",claude:"Claude Code",codex:"Codex",copilot:"GitHub Copilot",gemini:"Antigravity / Gemini",opencode:"OpenCode",kiro:"Kiro",pi:"Pi",hermes:"Hermes","agents-dir":"the shared ~/.agents folder",local:"ChatPanel",external:"a folder you added"});function G(n,{roster:e=[],chatModel:s=null,summary:t=null,attested:f=null,targets:h=[],teams:b=[],projects:g=[],dark:m=!1}={}){const i=n||{},a=String(i.id||""),l=x(i,{chatModel:s}),w=A(l)||{kind:l?.kind||"auto",id:""},k=r=>e.find(o=>o.kind==="bridge"&&(o.bridgeAgent||o.id)===r)?.name||u(r)?.label||r,y=r=>e.find(o=>o.id===r)?.name||r,d=v(i);return{id:a,name:String(i.name||a),purpose:String(i.purpose||""),avatar:{initials:$(i),color:R(a,{dark:m})},kind:E(i),trust:{level:d,label:c[d][0],why:c[d][1]},identity:S(i),engine:{label:C(l,{harnessName:k,providerName:y}),kind:l?.kind||"auto",ref:w},egress:j(l,i),badges:L(i),chips:{grants:(i.grants||[]).filter(r=>r!=="none").map(r=>({id:r,label:p[r]?.[0]||r,why:p[r]?.[1]||""})),skills:(i.skills||[]).map(r=>({id:r,label:r})),tags:(i.tags||[]).map(r=>({id:r,label:r}))},origin:U(i),where:{teams:b.filter(r=>(r?.roles||[]).some(o=>o?.agent===a)).map(r=>r.name),jobs:g.flatMap(r=>(r?.jobs||[]).filter(o=>o?.agentId===a).map(o=>o.title||o.id))},invoke:a?`/${a} <request>`:"",numbers:N(t,{attested:f}),portability:z(h),warnings:Array.isArray(i.warnings)?i.warnings:[]}}function S(n){const e=[];return n.provider?.organization&&e.push({key:"provider",label:"published by",value:n.provider.organization,href:n.provider.url||""}),n.version&&e.push({key:"version",label:"version",value:String(n.version)}),n.documentationUrl&&e.push({key:"docs",label:"documentation",value:n.documentationUrl,href:n.documentationUrl}),n.workdir&&e.push({key:"workdir",label:"works in",value:n.workdir}),e}function j(n,e){if(n?.kind!=="harness"||!n.harnessId)return null;const s=u(n.harnessId),t=I(n.harnessId,{repointed:e?.repointed??null});return{harness:n.harnessId,label:s?.label||n.harnessId,vendor:s?.vendor||null,egress:t.egress,where:t.where,note:t.note,repoint:s?.repoint||"unknown",how:s?.how||""}}function L(n){const e=[],s=n.capabilities||n.dialectExtras?.a2a?.card?.capabilities||{};s.streaming&&e.push({id:"streaming",label:"streams",title:"sends partial results as it works"}),s.pushNotifications&&e.push({id:"push",label:"webhooks",title:"can call back when a long task finishes"}),s.extendedAgentCard&&e.push({id:"extended",label:"extended card",title:"publishes more once you authenticate"});for(const t of s.extensions||[])e.push({id:`ext:${t.uri}`,label:t.required?"extension (required)":"extension",title:t.description||t.uri});return n.enabled===!1&&e.push({id:"off",label:"off",title:"switched off — it keeps its definition"}),e}function U(n){const e=n.origin;return e?.source?{source:e.source,label:O[e.source]||e.source,path:e.id||"",scanned:e.scanned||null}:null}function z(n){return(Array.isArray(n)?n:[]).map(e=>({id:e.id,label:e.label,filename:e.filename,lossless:!!e.lossless,dropped:e.dropped||[],summary:e.lossless?"carries everything":`${e.dropped.length} field${e.dropped.length===1?"":"s"} will not carry: ${e.dropped.map(s=>s.field).join(", ")}`}))}function _(n){const e=[n.engine.label];return n.egress?.egress==="internet"&&n.egress.vendor&&e.push(`talks to ${n.egress.vendor}`),n.origin&&e.push(`from ${n.origin.label}`),e.filter(Boolean).join(" · ")}export{O as SOURCE_LABEL,c as TRUST_LABEL,_ as agentCardLine,G as agentCardView};
1
+ import{agentTrust as v,engineOf as x}from"./agent.js";import{describeEngine as C,engineRef as A}from"./engine.js";import{harnessCard as u,harnessEgress as I}from"./harness-cards.js";import{agentColor as R,agentInitials as $,agentKind as E,cardNumbers as N,GRANT_INFO as p}from"./team-org.js";const c=Object.freeze({"built-in":["built-in","shipped with Chap and reviewed by us"],user:["yours","you wrote this one here"],community:["from a folder","it arrived in a directory on this machine — we cannot tell who wrote it"]}),O=Object.freeze({chatpanel:"ChatPanel",claude:"Claude Code",codex:"Codex",copilot:"GitHub Copilot",gemini:"Antigravity / Gemini",opencode:"OpenCode",kiro:"Kiro",pi:"Pi",hermes:"Hermes","agents-dir":"the shared ~/.agents folder",local:"ChatPanel",external:"a folder you added"});function P(n,{roster:e=[],chatModel:s=null,summary:t=null,attested:f=null,targets:h=[],teams:b=[],projects:g=[],dark:m=!1}={}){const i=n||{},a=String(i.id||""),l=x(i,{chatModel:s}),w=A(l)||{kind:l?.kind||"auto",id:""},k=r=>e.find(o=>o.kind==="bridge"&&(o.bridgeAgent||o.id)===r)?.name||u(r)?.label||r,y=r=>e.find(o=>o.id===r)?.name||r,d=v(i);return{id:a,name:String(i.name||a),purpose:String(i.purpose||""),avatar:{initials:$(i),color:R(a,{dark:m})},kind:E(i),trust:{level:d,label:c[d][0],why:c[d][1]},identity:S(i),engine:{label:C(l,{harnessName:k,providerName:y}),kind:l?.kind||"auto",ref:w},egress:j(l,i),badges:L(i),chips:{grants:(i.grants||[]).filter(r=>r!=="none").map(r=>({id:r,label:p[r]?.[0]||r,why:p[r]?.[1]||""})),skills:(i.skills||[]).map(r=>({id:r,label:r})),tags:(i.tags||[]).map(r=>({id:r,label:r}))},origin:U(i),where:{teams:b.filter(r=>(r?.roles||[]).some(o=>o?.agent===a)).map(r=>r.name),jobs:g.flatMap(r=>(r?.jobs||[]).filter(o=>o?.agentId===a).map(o=>o.title||o.id))},invoke:a?`/${a} <request>`:"",numbers:N(t,{attested:f}),portability:z(h),warnings:Array.isArray(i.warnings)?i.warnings:[]}}function S(n){const e=[];return n.provider?.organization&&e.push({key:"provider",label:"published by",value:n.provider.organization,href:n.provider.url||""}),n.version&&e.push({key:"version",label:"version",value:String(n.version)}),n.documentationUrl&&e.push({key:"docs",label:"documentation",value:n.documentationUrl,href:n.documentationUrl}),n.workdir&&e.push({key:"workdir",label:"works in",value:n.workdir}),e}function j(n,e){if(n?.kind!=="harness"||!n.harnessId)return null;const s=u(n.harnessId),t=I(n.harnessId,{repointed:e?.repointed??null});return{harness:n.harnessId,label:s?.label||n.harnessId,vendor:s?.vendor||null,egress:t.egress,where:t.where,note:t.note,repoint:s?.repoint||"unknown",how:s?.how||""}}function L(n){const e=[],s=n.capabilities||n.dialectExtras?.a2a?.card?.capabilities||{};s.streaming&&e.push({id:"streaming",label:"streams",title:"sends partial results as it works"}),s.pushNotifications&&e.push({id:"push",label:"webhooks",title:"can call back when a long task finishes"}),s.extendedAgentCard&&e.push({id:"extended",label:"extended card",title:"publishes more once you authenticate"});for(const t of s.extensions||[])e.push({id:`ext:${t.uri}`,label:t.required?"extension (required)":"extension",title:t.description||t.uri});return n.enabled===!1&&e.push({id:"off",label:"off",title:"switched off — it keeps its definition"}),e}function U(n){const e=n.origin;return e?.source?{source:e.source,label:O[e.source]||e.source,path:e.id||"",scanned:e.scanned||null}:null}function z(n){return(Array.isArray(n)?n:[]).map(e=>({id:e.id,label:e.label,filename:e.filename,lossless:!!e.lossless,dropped:e.dropped||[],summary:e.lossless?"carries everything":`${e.dropped.length} field${e.dropped.length===1?"":"s"} will not carry: ${e.dropped.map(s=>s.field).join(", ")}`}))}function _(n){const e=[n.engine.label];return n.egress?.egress==="internet"&&n.egress.vendor&&e.push(`talks to ${n.egress.vendor}`),n.origin&&e.push(`from ${n.origin.label}`),e.filter(Boolean).join(" · ")}export{O as SOURCE_LABEL,c as TRUST_LABEL,_ as agentCardLine,P as agentCardView};
@@ -1,2 +1,2 @@
1
- const x="permission_request",f=Object.freeze({ALLOW:"allow",ALLOW_CHAT:"allow_chat",DENY:"deny"}),O=600*1e3,A="permission_prompt";function w(){return{name:A,description:"ChatPanel-internal: the person answers the agent's permission prompt. Not for the model.",parameters:{type:"object",properties:{tool:{type:"string"},input:{type:"object"},description:{type:"string"},path:{type:"string"},rules:{type:"array"}}}}}const $=e=>e===A,u=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),a=e=>typeof e=="string"?e:e==null?"":String(e);function P(e={}){const t=u(e)?e:{},o=a(t.tool_name||t.toolName||t.tool),n=[];for(const s of Array.isArray(t.permission_suggestions)?t.permission_suggestions:[])if(!(!u(s)||s.type!=="addRules"||s.behavior==="deny"))for(const i of Array.isArray(s.rules)?s.rules:[]){if(!u(i))continue;const c=a(i.toolName||o),l=a(i.ruleContent);c&&!n.some(d=>d.tool===c&&d.content===l)&&n.push({tool:c,content:l})}return{tool:o,displayName:a(t.display_name||t.displayName)||o,input:u(t.input)?t.input:{},description:a(t.description),path:a(t.blocked_path||t.path)||null,rules:n,toolUseId:a(t.tool_use_id||t.toolUseId)||null}}function y(e={}){const t=Array.isArray(e.rules)?e.rules.filter(o=>o&&o.tool):[];return t.length?t.map(o=>o.content?`${o.tool}(${o.content})`:o.tool):e.tool?[String(e.tool)]:[]}function _(e={}){const t=a(e.tool),o=u(e.input)?e.input:{},n=(r,p=240)=>r.length>p?`${r.slice(0,p-1)}…`:r;let s,i;if(t==="Bash")s="Run a command",i=n(a(o.command).trim()||a(e.description)||"a shell command");else if(t==="Edit"||t==="MultiEdit"||t==="NotebookEdit")s="Edit a file",i=a(o.file_path||o.notebook_path||e.path)||"a file";else if(t==="Write"){s="Write a file";const r=a(o.file_path||e.path)||"a file",p=a(o.content).length;i=p?`${r} (${p.toLocaleString()} chars)`:r}else if(/^mcp__/.test(t))s="Use a connected server",i=t.replace(/^mcp__/,"").replace(/__/," › ");else{s=`Use ${e.displayName||t||"a tool"}`;let r="";try{r=JSON.stringify(o)}catch{r=""}i=a(e.description)||(r&&r!=="{}"?n(r,200):t)}const c=y(e),l=Array.isArray(e.rules)?e.rules.filter(r=>r?.content):[],d=l.length&&l.some(r=>r.content!==i)?l.map(r=>r.content).join(", "):c.length&&!l.length?`every ${t} call`:null;return{title:s,detail:i,scope:d,description:a(e.description)||null}}function m(e,t=""){return e===f.ALLOW?{behavior:"allow",scope:"once"}:e===f.ALLOW_CHAT?{behavior:"allow",scope:"chat"}:{behavior:"deny",scope:"once",...t?{message:String(t)}:{}}}function b(e){return u(e)&&e.behavior==="allow"}function N(e,t){const o=new Set(Array.isArray(e)?e:[]);for(const n of y(t))o.add(n);return[...o].sort()}function E(e,t){const o=y(t);if(!o.length)return null;const n=new Set(Array.isArray(e)?e:[]);return o.every(s=>n.has(s))?m(f.ALLOW):null}function k(e,t,o={}){const n=u(o)?o:{},s=b(t);let i;if(s){if(i={behavior:"allow",updatedInput:u(n.input)?n.input:{}},t.scope==="chat"){const c=(Array.isArray(n.permission_suggestions)?n.permission_suggestions:[]).filter(l=>u(l)&&l.type==="addRules"&&l.behavior!=="deny"&&Array.isArray(l.rules)&&l.rules.length).map(l=>({type:"addRules",rules:l.rules,behavior:"allow",destination:"session"}));c.length&&(i.updatedPermissions=c)}}else i={behavior:"deny",message:a(t?.message)||"The user declined this action in ChatPanel. Continue without it, or explain what it was for and ask."};return{type:"control_response",response:{subtype:"success",request_id:String(e),response:i}}}function R(e,t){const{detail:o}=_(e),n=b(t),s=n&&t.scope==="chat"?" for this chat":"";return`${n?"Allowed":"Declined"}${s}: ${o}`}function L(e){return e==="Bash"?"code":/^(Edit|MultiEdit|NotebookEdit)$/.test(String(e))?"pencil":e==="Write"?"file":/^mcp__/.test(String(e))?"plug":"bot"}function T(){const e=new Map;async function t(o,{convId:n=null,confirm:s,agentName:i="The agent"}={}){const c=E(e.get(n)||[],o);if(c)return c;const{title:l,detail:d,scope:r,description:p}=_(o),S=[d,p&&p!==d?p:"",r?`“Allow for this chat” also covers: ${r}`:""].filter(Boolean).join(`
2
- `);let h;try{if(typeof s!="function")throw new Error("no card");h=await s(S,{title:`${i} asks — ${l.toLowerCase()}?`,iconName:L(o.tool),scopeLabel:"Allow for this chat"})}catch(g){return m(f.DENY,`ChatPanel could not show the permission card (${g?.message||g}).`)}return h==="site"||h==="always"?(e.set(n,N(e.get(n)||[],o)),m(f.ALLOW_CHAT)):m(h==="allow"?f.ALLOW:f.DENY)}return{ask:t,forget(o){e.delete(o)},standing(o){return e.get(o)||[]},provider({convId:o=null,confirm:n,agentName:s="The agent"}={}){return{id:"permission",specs:[w()],execute:async(i,c)=>JSON.stringify(await t(c&&typeof c=="object"?c:{},{convId:o,confirm:n,agentName:s}))}}}}export{f as PERMISSION_ANSWERS,x as PERMISSION_EVENT,O as PERMISSION_TIMEOUT_MS,A as PERMISSION_TOOL_NAME,k as claudePermissionResponse,T as createPermissionDesk,_ as describePermission,$ as isPermissionTool,b as permissionAllowed,m as permissionAnswer,L as permissionIcon,y as permissionKeys,R as permissionLine,P as permissionRequestFromClaude,w as permissionToolSpec,E as recallPermission,N as rememberPermission};
1
+ const $="permission_request",p=Object.freeze({ALLOW:"allow",ALLOW_CHAT:"allow_chat",DENY:"deny"}),W=600*1e3,_="permission_prompt";function N(){return{name:_,description:"Chap-internal: the person answers the agent's permission prompt. Not for the model.",parameters:{type:"object",properties:{tool:{type:"string"},input:{type:"object"},description:{type:"string"},path:{type:"string"},rules:{type:"array"}}}}}const T=t=>t===_,u=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),a=t=>typeof t=="string"?t:t==null?"":String(t);function k(t={}){const e=u(t)?t:{},o=a(e.tool_name||e.toolName||e.tool),n=[];for(const s of Array.isArray(e.permission_suggestions)?e.permission_suggestions:[])if(!(!u(s)||s.type!=="addRules"||s.behavior==="deny"))for(const r of Array.isArray(s.rules)?s.rules:[]){if(!u(r))continue;const c=a(r.toolName||o),i=a(r.ruleContent);c&&!n.some(f=>f.tool===c&&f.content===i)&&n.push({tool:c,content:i})}return{tool:o,displayName:a(e.display_name||e.displayName)||o,input:u(e.input)?e.input:{},description:a(e.description),path:a(e.blocked_path||e.path)||null,rules:n,toolUseId:a(e.tool_use_id||e.toolUseId)||null}}function g(t={}){const e=Array.isArray(t.rules)?t.rules.filter(o=>o&&o.tool):[];return e.length?e.map(o=>o.content?`${o.tool}(${o.content})`:o.tool):t.tool?[String(t.tool)]:[]}function L(t={}){const e=a(t.tool),o=u(t.input)?t.input:{},n=(l,d=240)=>l.length>d?`${l.slice(0,d-1)}…`:l;let s,r;if(e==="Bash")s="Run a command",r=n(a(o.command).trim()||a(t.description)||"a shell command");else if(e==="Edit"||e==="MultiEdit"||e==="NotebookEdit")s="Edit a file",r=a(o.file_path||o.notebook_path||t.path)||"a file";else if(e==="Write"){s="Write a file";const l=a(o.file_path||t.path)||"a file",d=a(o.content).length;r=d?`${l} (${d.toLocaleString()} chars)`:l}else if(/^mcp__/.test(e))s="Use a connected server",r=e.replace(/^mcp__/,"").replace(/__/," › ");else{s=`Use ${t.displayName||e||"a tool"}`;let l="";try{l=JSON.stringify(o)}catch{l=""}r=a(t.description)||(l&&l!=="{}"?n(l,200):e)}const c=g(t),i=Array.isArray(t.rules)?t.rules.filter(l=>l?.content):[],f=i.length&&i.some(l=>l.content!==r)?i.map(l=>l.content).join(", "):c.length&&!i.length?`every ${e} call`:null;return{title:s,detail:r,scope:f,description:a(t.description)||null}}function h(t,e=""){return t===p.ALLOW?{behavior:"allow",scope:"once"}:t===p.ALLOW_CHAT?{behavior:"allow",scope:"chat"}:{behavior:"deny",scope:"once",...e?{message:String(e)}:{}}}function w(t){return u(t)&&t.behavior==="allow"}function E(t,e){const o=new Set(Array.isArray(t)?t:[]);for(const n of g(e))o.add(n);return[...o].sort()}const b="*";function O(t,e){const o=new Set(Array.isArray(t)?t:[]);if(o.has(b))return h(p.ALLOW);const n=g(e);return n.length&&n.every(s=>o.has(s))?h(p.ALLOW):null}function R(t,e,o={}){const n=u(o)?o:{},s=w(e);let r;if(s){if(r={behavior:"allow",updatedInput:u(n.input)?n.input:{}},e.scope==="chat"){const c=(Array.isArray(n.permission_suggestions)?n.permission_suggestions:[]).filter(i=>u(i)&&i.type==="addRules"&&i.behavior!=="deny"&&Array.isArray(i.rules)&&i.rules.length).map(i=>({type:"addRules",rules:i.rules,behavior:"allow",destination:"session"}));c.length&&(r.updatedPermissions=c)}}else r={behavior:"deny",message:a(e?.message)||"The user declined this action in Chap. Continue without it, or explain what it was for and ask."};return{type:"control_response",response:{subtype:"success",request_id:String(t),response:r}}}function C(t,e){const{detail:o}=L(t),n=w(e),s=n&&e.scope==="chat"?" for this chat":"";return`${n?"Allowed":"Declined"}${s}: ${o}`}function x(t){return t==="Bash"?"code":/^(Edit|MultiEdit|NotebookEdit)$/.test(String(t))?"pencil":t==="Write"?"file":/^mcp__/.test(String(t))?"plug":"bot"}function P({memory:t=new Map}={}){const e=t;async function o(n,{convId:s=null,confirm:r,agentName:c="The agent"}={}){const i=O(await e.get(s)||[],n);if(i)return i;const{title:f,detail:l,scope:d,description:y}=L(n),S=[l,y&&y!==l?y:"",d?`“Allow for this chat” also covers: ${d}`:""].filter(Boolean).join(`
2
+ `);let m;try{if(typeof r!="function")throw new Error("no card");m=await r(S,{title:`${c} asks — ${f.toLowerCase()}?`,iconName:x(n.tool),scopeLabel:"Allow for this chat",allLabel:"Allow all in this chat"})}catch(A){return h(p.DENY,`Chap could not show the permission card (${A?.message||A}).`)}return m==="all"?(await e.set(s,[b]),h(p.ALLOW_CHAT)):m==="site"||m==="always"?(await e.set(s,E(await e.get(s)||[],n)),h(p.ALLOW_CHAT)):h(m==="allow"?p.ALLOW:p.DENY)}return{ask:o,forget(n){e.delete(n)},standing(n){return e.get(n)||[]},provider({convId:n=null,confirm:s,agentName:r="The agent"}={}){return{id:"permission",specs:[N()],execute:async(c,i)=>JSON.stringify(await o(i&&typeof i=="object"?i:{},{convId:n,confirm:s,agentName:r}))}}}}export{b as ALLOW_ALL,p as PERMISSION_ANSWERS,$ as PERMISSION_EVENT,W as PERMISSION_TIMEOUT_MS,_ as PERMISSION_TOOL_NAME,R as claudePermissionResponse,P as createPermissionDesk,L as describePermission,T as isPermissionTool,w as permissionAllowed,h as permissionAnswer,x as permissionIcon,g as permissionKeys,C as permissionLine,k as permissionRequestFromClaude,N as permissionToolSpec,O as recallPermission,E as rememberPermission};
@@ -0,0 +1 @@
1
+ import{makeRecordId as g}from"./library.js";const u=Object.freeze([Object.freeze({id:"claude",label:"Claude Code"}),Object.freeze({id:"codex",label:"Codex"})]),d=Object.fromEntries(u.map(e=>[e.id,e.label])),A=Object.freeze([{command:"resume",icon:"↺",description:"Open a Claude Code or Codex session — one you had in its own app too — and continue it here",typed:!0}]);function x(e){const t=/^\/(resume|sessions)(?:\s+(\S+))?\s*$/i.exec(String(e||"").trim());if(!t)return null;const n=String(t[2]||"").toLowerCase().replace(/[^a-z]/g,""),r=n?u.find(o=>o.id===n||o.label.toLowerCase().replace(/[^a-z]/g,"")===n)?.id:null;return n&&!r?null:{agent:r||null}}function p(e,t){const n=Math.max(0,Math.round((t-e)/1e3));if(n<60)return"just now";const r=Math.round(n/60);if(r<60)return`${r} min ago`;const o=Math.round(r/60);if(o<24)return`${o} h ago`;const s=Math.round(o/24);return s===1?"yesterday":`${s} days ago`}function f(e){return String(e||"").split(/[\\/]+/).filter(Boolean).at(-1)||""}function b(e,{now:t=Date.now()}={}){const n=[d[e?.agent]||e?.agent||"Agent",f(e?.cwd),e?.live?"also open in another window":e?.updatedAt?p(Number(e.updatedAt),t):""].filter(Boolean);return{title:String(e?.title||"Untitled session"),detail:n.join(" · "),open:e?.thread||null}}function y(...e){return e.flat().filter(Boolean).sort((t,n)=>(Number(n.updatedAt)||0)-(Number(t.updatedAt)||0))}function C(e,{localId:t,now:n=Date.now(),messageId:r=o=>`${t}-m${o}`}={}){if(!e||!Array.isArray(e.messages))throw new Error("sessionToChat: a session with messages");if(!t)throw new Error("sessionToChat: localId required");return{id:g("chat",t),kind:"chat",localId:t,title:String(e.title||"").trim()||`${d[e.agent]||"Agent"} session`,tags:[],createdAt:n,updatedAt:n,deletedAt:0,body:{messages:e.messages.map((o,s)=>({id:r(s),role:o.role==="assistant"?"assistant":"user",content:String(o.content||""),ts:n})),agentSession:{agent:e.agent,sessionId:e.id,cwd:String(e.cwd||"")}},meta:{}}}function w(e,t=""){const n=String(e?.agentSession?.cwd||"").trim();return n&&/^([A-Za-z]:[\\/]|\/)/.test(n)?n:String(t||"")}function S(e){const t=e?.agentSession?.agent;return d[t]?t:null}function O(e,t=""){const n=S(e);if(n)return n;const r=String(t||e?.model||"").split("|").pop().split("/")[0].trim().toLowerCase();return r==="claude"||r==="claude-code"?"claude":r==="codex"?"codex":null}function m(e=[]){return(Array.isArray(e)?e:[]).filter(t=>t&&(t.role==="user"||t.role==="assistant")&&!t.hidden&&!t.pending&&!t.error&&String(t.content||"").trim()).map(t=>({role:t.role,content:String(t.content)}))}async function $(e,{thread:t,agent:n,post:r,now:o=Date.now(),newId:s=a=>`o${o.toString(36)}${a}`}={}){const a=m(e?.messages);if(!n||!t||!a.length||typeof r!="function")return[];const c=await r("/agent-sessions/catchup",{agent:n,thread:{id:String(t)},messages:a});return(Array.isArray(c?.messages)?c.messages:[]).filter(i=>i&&(i.role==="user"||i.role==="assistant")).map((i,l)=>({id:s(l),role:i.role,content:String(i.content??""),ts:o,via:{app:n}}))}export{A as SESSIONS_SLASH_ITEMS,u as SESSION_AGENTS,p as ago,$ as catchUpChat,S as conversationAgent,w as conversationWorkdir,b as describeSession,f as folderName,m as heldMessages,y as mergeSessionLists,x as parseSessionsCommand,O as sessionAgentOf,C as sessionToChat};
@@ -0,0 +1,5 @@
1
+ import{EventError as p}from"./event.js";const y=(t,r)=>{if(!t)throw new p("SHAPE",r)},m=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;function I(t){if(!t||typeof t!="object")return null;const r=String(t.id??"").trim().replace(/^chat:/,"");if(!m.test(r))return null;const n=String(t.title??"").replace(/[\u0000-\u001f\u007f]+/g," ").replace(/\s+/g," ").trim().slice(0,120);return{id:r,...n?{title:n}:{}}}function E(t){return t?[`chat:${t}`]:[]}function x(t=[]){const n=(Array.isArray(t)?t:[]).slice(0,-1);return{users:n.filter(e=>e?.role==="user").map(e=>l(e.content).trim()),answers:n.filter(e=>e?.role==="assistant").length}}function A(t=[],{answered:r=!0}={}){const n=Array.isArray(t)?t:[];return{users:n.filter(e=>e?.role==="user").map(e=>l(e.content).trim()),answers:n.filter(e=>e?.role==="assistant").length+(r?1:0)}}const g=8;function h(t,r=g){const n=String(t??"").trim(),e=[n];let s=n;for(let i=0;i<r;i++){const o=s.lastIndexOf(`
2
+
3
+ `);if(o<0)break;s=s.slice(0,o).trim(),s&&e.push(s)}return[...new Set(e)]}function w(t,r){const n=String(r??"").trim();return h(t).includes(n)}function b(t=[],{answered:r=!0}={}){const n=A(t,{answered:r});return{users:n.users.slice(0,-1),answers:n.answers,last:h(n.users.at(-1)??"")}}function P(t=[]){const r=x(t);return{users:r.users.slice(0,-1),answers:r.answers,last:r.users.at(-1)??null}}function T(t=[],{n:r,answers:n}={}){const e=Array.isArray(t)?t:[];if(!Number.isInteger(r)||r<0||!Number.isInteger(n)||n<0)return null;const s=[];let i=0,o=-1;for(let f=0;f<e.length;f++){const c=e[f];if(c?.role==="user"){if(s.length===r){o=f;break}s.push(l(c.content).trim())}else c?.role==="assistant"&&i++}if(o<0)return null;const u=n-i;if(u!==0&&u!==1)return null;let a=o+1;if(u===1){for(;a<e.length&&e[a]?.role!=="assistant";){if(e[a]?.role==="user")return null;a++}if(a>=e.length)return null;a++}const d=e.slice(a);return d.at(-1)?.role!=="user"?null:{prefix:{users:s,answers:n},last:l(e[o].content).trim(),tail:d,answered:u===1}}function D(t=[],r=()=>!1,{answered:n=!0}={}){const e=Array.isArray(t)?t:[];for(let s=e.length-1;s>=0;s--){if(e[s]?.role!=="user"||!r(l(e[s].content).trim()))continue;let i=s+1;n&&e[i]?.role==="assistant"&&i++;const o=e.slice(i).filter(u=>u?.role==="user"||u?.role==="assistant");return o.at(-1)?.role==="user"&&o.pop(),o}return[]}function _(t=[],r=[]){let n=Array.isArray(t)?t:[];for(const e of Array.isArray(r)?r:[]){if(e?.role!=="user")continue;const s=n.findIndex(i=>i?.role==="user"&&w(l(i.content),l(e.content)));s>=0&&(n=[...n.slice(0,s),...n.slice(s+1)])}return n}function z(t=[]){const r=Array.isArray(t)?t:[],n=r.filter(e=>e?.role==="user").map(e=>l(e.content).trim());return{users:n.slice(0,-1),answers:r.filter(e=>e?.role==="assistant").length,last:h(n.at(-1)??"")}}function l(t){return typeof t=="string"?t:Array.isArray(t)?t.map(r=>typeof r=="string"?r:r?.text||"").filter(Boolean).join(`
4
+
5
+ `):String(t??"")}function N({link:t=null,digest:r="",cwd:n="",hasHistory:e=!1}={}){return y(typeof r=="string","threadPlan: digest must be a string"),!t||!t.sessionId?{mode:"start",sessionId:null,seed:!!e,why:"no session holds this thread yet"}:String(t.cwd||"")!==String(n||"")?{mode:"start",sessionId:null,seed:!!e,why:"the thread moved to another folder"}:!r||t.digest!==r?{mode:"start",sessionId:null,seed:!!e,why:"the history differs from what the session saw (edited or regenerated)"}:{mode:"resume",sessionId:String(t.sessionId),seed:!1,why:"the session has seen exactly this history"}}export{T as historyExtension,x as historyShape,P as historySplit,E as legacyThreadIds,A as nextShape,I as normalizeThread,_ as outsideBeyond,D as outsideTurns,z as seenOf,h as sentVariants,N as threadPlan,b as turnSeen,w as userTextMatches};
package/attached-paths.js CHANGED
@@ -1,4 +1,4 @@
1
- import{formatBytes as C}from"./observability.js";import{SECRET_DIR_NAMES as de,SECRET_DIR_PAIRS as fe,SECRET_FILE_RES as pe,SECRET_FILE_ALLOW as me}from"./secret-names.js";import{SECRET_DIR_NAMES as He,SECRET_DIR_PAIRS as Le,SECRET_FILE_RES as Fe}from"./secret-names.js";const xe=300,j=4,q=4*1024*1024,X=12e3,Y=6e4,J=2e3,Q=24*1024*1024,ee=1024*1024,te=40,K=64*1024*1024,ne=3,G=300,z=4096,H="path",L="files",ge=[/^\/(etc|dev|proc|sys|boot|System|sbin|bin|usr\/(bin|sbin|lib))(\/|$)/,/^\/private\/(etc|var\/root|var\/db)(\/|$)/,/^\/(var\/root|Library\/Keychains|Library\/Security)(\/|$)/,/^[a-z]:\/(windows|program files|program files \(x86\)|programdata\/microsoft\/crypto)(\/|$)/i],$e=new Set(["node_modules",".git",".hg",".svn","__pycache__",".venv","venv",".tox",".cache",".next",".nuxt",".gradle",".idea",".mypy_cache",".pytest_cache",".turbo",".parcel-cache","bower_components",".terraform"]),ye=new Set([".DS_Store","Thumbs.db","desktop.ini"]);function S(e){let t=String(e||"").replace(/\\/g,"/").replace(/\/{2,}/g,"/");return t.length>1&&t.endsWith("/")&&!/^[a-z]:\/$/i.test(t)&&(t=t.slice(0,-1)),t}function re(e){return/^\//.test(e)||/^[a-z]:\//i.test(e)}function we(e,t){const r=S(t);return r?e==="~"?r:e.startsWith("~/")?`${r}${e.slice(1)}`:e:e}function ae(e){const t=S(e),r=/^([a-z]:\/|\/)?(.*)$/i.exec(t),a=r[1]||"",i=[];for(const s of(r[2]||"").split("/"))if(!(!s||s===".")){if(s===".."){i.length&&i.pop();continue}i.push(s)}return`${a}${i.join("/")}`||a||"."}function F(e){const t=S(e),r=t.lastIndexOf("/");return r<0?t:t.slice(r+1)||t}function U(e){const t=/\.([a-z0-9]{1,8})$/i.exec(String(e||""));return t?t[1].toLowerCase():""}function be(e){return e==="/"||/^[a-z]:\/?$/i.test(e)||/^\/(Users|home|Volumes|mnt)$/.test(e)||/^[a-z]:\/Users$/i.test(e)}function V(e,t){return!e||!t?!1:/^[a-z]:\//i.test(e)?e.toLowerCase()===t.toLowerCase():e===t}function O(e){const r=S(e).split("/").filter(Boolean);for(let i=0;i<r.length;i+=1){if(de.has(r[i]))return`\`${r[i]}\` holds credentials`;if(i+1<r.length&&fe.some(([s,A])=>s===r[i]&&A===r[i+1]))return`\`${r[i]}/${r[i+1]}\` holds credentials`}const a=r[r.length-1]||"";return a&&!me.test(a)&&pe.some(i=>i.test(a))?`\`${a}\` looks like a credential or key file`:""}const Ne=e=>!!O(e);function ve(e,{home:t="",cwd:r=""}={}){const a=k=>({ok:!1,reason:k}),i=String(e||"").trim();if(!i)return a("no path given");if(i.includes("\0"))return a("not a valid path");let s=S(we(i,t));const A=!t&&(s==="~"||s.startsWith("~/"));if(!A&&!re(s)){if(!r)return a("give an absolute path (or one starting with ~/)");s=`${S(r)}/${s}`}if(s=A?`~${ae(`/${s.slice(1)}`)}`.replace(/^~\/$/,"~"):ae(s),be(s))return a("that is the whole disk — attach a folder inside it");if(s==="~"||t&&V(s,S(t)))return a("that is your whole home folder — attach a folder inside it");if(ge.some(k=>k.test(s)))return a("system files are not attachable");const _=O(s);return _?a(`${_} — ChatPanel never reads those`):{ok:!0,path:s}}function ie(e,t=""){const r=S(e),a=S(t);return a&&(r===a||r.startsWith(`${a}/`))?`~${r.slice(a.length)}`:r}function W(e){if(e?.isDir==null)return"file or folder, as typed — not checked here";if(e.isDir){const i=Number(e.entries);return Number.isFinite(i)&&i>0?`folder, ${e.entriesTruncated?"more than ":"about "}${i.toLocaleString()} entries`:"folder"}const t=e?.ext||U(e?.title||e?.path),r=e?.type&&e.type!==t?` — actually ${e.type}`:"",a=Number(e?.pages)>0?`, ${Number(e.pages).toLocaleString()} page${e.pages===1?"":"s"}`:"";return`file, ${C(e?.size)}${t?`, .${t}`:""}${r}${a}`}function se(e,{absolute:t=!1,home:r=""}={}){const a=e.isDir==null?"Path":e.isDir?"Folder":"File";if(e.reach==="tool")return`Attached by reference — its contents are NOT in this conversation.
1
+ import{formatBytes as C}from"./observability.js";import{SECRET_DIR_NAMES as de,SECRET_DIR_PAIRS as fe,SECRET_FILE_RES as pe,SECRET_FILE_ALLOW as me}from"./secret-names.js";import{SECRET_DIR_NAMES as He,SECRET_DIR_PAIRS as Le,SECRET_FILE_RES as Fe}from"./secret-names.js";const xe=300,j=4,q=4*1024*1024,X=12e3,Y=6e4,J=2e3,Q=24*1024*1024,ee=1024*1024,te=40,K=64*1024*1024,ne=3,G=300,z=4096,H="path",L="files",ge=[/^\/(etc|dev|proc|sys|boot|System|sbin|bin|usr\/(bin|sbin|lib))(\/|$)/,/^\/private\/(etc|var\/root|var\/db)(\/|$)/,/^\/(var\/root|Library\/Keychains|Library\/Security)(\/|$)/,/^[a-z]:\/(windows|program files|program files \(x86\)|programdata\/microsoft\/crypto)(\/|$)/i],$e=new Set(["node_modules",".git",".hg",".svn","__pycache__",".venv","venv",".tox",".cache",".next",".nuxt",".gradle",".idea",".mypy_cache",".pytest_cache",".turbo",".parcel-cache","bower_components",".terraform"]),ye=new Set([".DS_Store","Thumbs.db","desktop.ini"]);function S(e){let t=String(e||"").replace(/\\/g,"/").replace(/\/{2,}/g,"/");return t.length>1&&t.endsWith("/")&&!/^[a-z]:\/$/i.test(t)&&(t=t.slice(0,-1)),t}function re(e){return/^\//.test(e)||/^[a-z]:\//i.test(e)}function we(e,t){const r=S(t);return r?e==="~"?r:e.startsWith("~/")?`${r}${e.slice(1)}`:e:e}function ae(e){const t=S(e),r=/^([a-z]:\/|\/)?(.*)$/i.exec(t),a=r[1]||"",i=[];for(const s of(r[2]||"").split("/"))if(!(!s||s===".")){if(s===".."){i.length&&i.pop();continue}i.push(s)}return`${a}${i.join("/")}`||a||"."}function F(e){const t=S(e),r=t.lastIndexOf("/");return r<0?t:t.slice(r+1)||t}function U(e){const t=/\.([a-z0-9]{1,8})$/i.exec(String(e||""));return t?t[1].toLowerCase():""}function be(e){return e==="/"||/^[a-z]:\/?$/i.test(e)||/^\/(Users|home|Volumes|mnt)$/.test(e)||/^[a-z]:\/Users$/i.test(e)}function V(e,t){return!e||!t?!1:/^[a-z]:\//i.test(e)?e.toLowerCase()===t.toLowerCase():e===t}function O(e){const r=S(e).split("/").filter(Boolean);for(let i=0;i<r.length;i+=1){if(de.has(r[i]))return`\`${r[i]}\` holds credentials`;if(i+1<r.length&&fe.some(([s,A])=>s===r[i]&&A===r[i+1]))return`\`${r[i]}/${r[i+1]}\` holds credentials`}const a=r[r.length-1]||"";return a&&!me.test(a)&&pe.some(i=>i.test(a))?`\`${a}\` looks like a credential or key file`:""}const Ne=e=>!!O(e);function ve(e,{home:t="",cwd:r=""}={}){const a=k=>({ok:!1,reason:k}),i=String(e||"").trim();if(!i)return a("no path given");if(i.includes("\0"))return a("not a valid path");let s=S(we(i,t));const A=!t&&(s==="~"||s.startsWith("~/"));if(!A&&!re(s)){if(!r)return a("give an absolute path (or one starting with ~/)");s=`${S(r)}/${s}`}if(s=A?`~${ae(`/${s.slice(1)}`)}`.replace(/^~\/$/,"~"):ae(s),be(s))return a("that is the whole disk — attach a folder inside it");if(s==="~"||t&&V(s,S(t)))return a("that is your whole home folder — attach a folder inside it");if(ge.some(k=>k.test(s)))return a("system files are not attachable");const _=O(s);return _?a(`${_} — Chap never reads those`):{ok:!0,path:s}}function ie(e,t=""){const r=S(e),a=S(t);return a&&(r===a||r.startsWith(`${a}/`))?`~${r.slice(a.length)}`:r}function W(e){if(e?.isDir==null)return"file or folder, as typed — not checked here";if(e.isDir){const i=Number(e.entries);return Number.isFinite(i)&&i>0?`folder, ${e.entriesTruncated?"more than ":"about "}${i.toLocaleString()} entries`:"folder"}const t=e?.ext||U(e?.title||e?.path),r=e?.type&&e.type!==t?` — actually ${e.type}`:"",a=Number(e?.pages)>0?`, ${Number(e.pages).toLocaleString()} page${e.pages===1?"":"s"}`:"";return`file, ${C(e?.size)}${t?`, .${t}`:""}${r}${a}`}function se(e,{absolute:t=!1,home:r=""}={}){const a=e.isDir==null?"Path":e.isDir?"Folder":"File";if(e.reach==="tool")return`Attached by reference — its contents are NOT in this conversation.
2
2
  ${a}: ${e.title||F(e.path)} (${W(e)})
3
3
  It is not at a path you can open; read only what the question needs from it with the \`files\` tool (list, read, search). Do not read all of it unasked.`;const i=t?S(e.path):ie(e.path,r);return`Attached by reference — its contents are NOT in this conversation.
4
4
  ${a}: ${i} (${W(e)})
package/browser-relay.js CHANGED
@@ -1 +1 @@
1
- const l=Object.freeze({maxPending:8,callMs:12e4,maxCallMs:6e5,maxArgsChars:64e3,maxResultChars:1e6,maxSpecChars:64e3,maxActionsChars:96e3,maxSystemChars:16e3,maxTaskChars:200}),g=Object.freeze(["chrome","edge","firefox","brave","opera","chromium","other"]),h=/^[a-z][a-z0-9_]{0,63}$/,f=e=>e!=null&&typeof e=="object"&&!Array.isArray(e),u=e=>{try{return JSON.stringify(e??null).length}catch{return 1/0}};function w(e){if(!f(e))return{ok:!1,error:"body must be a JSON object"};const r=String(e.action||"");if(!h.test(r))return{ok:!1,error:"action must be a page action name (e.g. open_tab, read_page, fill_form)"};const t=e.args==null?{}:e.args;if(!f(t))return{ok:!1,error:"args must be an object"};if(u(t)>l.maxArgsChars)return{ok:!1,error:"args too large"};const n=String(e.task||"").replace(/\s+/g," ").trim().slice(0,l.maxTaskChars),i=Number(e.timeoutMs),s=Number.isFinite(i)&&i>0?Math.min(i,l.maxCallMs):l.callMs;return{ok:!0,call:{action:r,args:t,task:n,timeoutMs:s}}}function k(e){if(!f(e))return{ok:!1,error:"body must be a JSON object"};const r=String(e.session||"");if(!r)return{ok:!1,error:"session required"};const t=g.includes(e.browser?.kind)?e.browser.kind:"other",n=String(e.browser?.version||"").slice(0,40),i=e.spec;if(!f(i)||typeof i.name!="string"||!f(i.parameters))return{ok:!1,error:"spec must be a tool spec { name, description, parameters }"};if(u(i)>l.maxSpecChars)return{ok:!1,error:"spec too large"};const s=String(e.system||"").slice(0,l.maxSystemChars),o=String(e.extension||"").slice(0,40);let a=[];if(e.actions!=null){if(!Array.isArray(e.actions)||!e.actions.every(c=>f(c)&&typeof c.name=="string"&&h.test(c.name)))return{ok:!1,error:"actions must be tool specs { name, description, parameters }"};if(u(e.actions)>l.maxActionsChars)return{ok:!1,error:"actions too large"};a=e.actions}return{ok:!0,announce:{session:r,browser:{kind:t,version:n},spec:i,system:s,extension:o,actions:a}}}function x(e){if(!f(e))return{ok:!1,error:"body must be a JSON object"};const r=String(e.session||""),t=String(e.id||"");if(!r||!t)return{ok:!1,error:"session and id required"};const n=e.result;return typeof n=="string"||f(n)&&typeof n.text=="string"&&(n.image==null||typeof n.image=="string")?u(n)>l.maxResultChars?{ok:!1,error:"result too large"}:{ok:!0,answer:{session:r,id:t,result:n}}:{ok:!1,error:"result must be a string or { text, image? }"}}function b({newId:e}={}){if(typeof e!="function")throw new Error("createBrowserRelay: newId required");let r=null;const t=new Map,n=(s,o)=>{const a=t.get(s);return a?(t.delete(s),a.resolve(o),!0):!1},i=(s,o,a)=>{for(const[c,m]of t)m.session===s&&n(c,{ok:!1,error:o,code:a})};return{connect(s){if(typeof s!="function")throw new Error("connect: send required");if(r){const o=r;i(o.session,"The browser reconnected; the call was lost. Try it again.","reconnected");try{o.send("replaced",{})}catch{}}return r={session:e(),send:s,offer:null},r.session},announce(s){return!r||s?.session!==r.session?!1:(r.offer={browser:s.browser,spec:s.spec,system:s.system,extension:s.extension||"",actions:Array.isArray(s.actions)?s.actions:[]},!0)},disconnect(s){return!r||r.session!==s?!1:(i(s,"The browser disconnected (the ChatPanel panel was closed). Ask the user to open it and try again.","disconnected"),r=null,!0)},status(){return r?.offer?{connected:!0,browser:r.offer.browser,extension:r.offer.extension,spec:r.offer.spec,system:r.offer.system,actions:r.offer.actions,pending:t.size}:{connected:!1,pending:t.size,...r?{waiting:!0}:{}}},call({action:s,args:o={},task:a=""}){if(!r?.offer)return{id:null,done:Promise.resolve({ok:!1,error:"No browser is connected. Ask the user to open the ChatPanel side panel in their browser (Chrome, Edge or Firefox) and try again.",code:"not_connected"})};if(t.size>=l.maxPending)return{id:null,done:Promise.resolve({ok:!1,error:"The browser is busy with other calls; wait for them to finish.",code:"busy"})};const c=e(),m=r.session,p=new Promise(d=>t.set(c,{session:m,resolve:d}));try{r.send("call",{id:c,action:s,args:o,task:a})}catch{n(c,{ok:!1,error:"The browser stream closed while sending the call.",code:"disconnected"})}return{id:c,done:p}},answer({session:s,id:o,result:a}){const c=t.get(o);return!c||c.session!==s?!1:n(o,{ok:!0,result:a})},expire(s,o=l.callMs){const a=t.get(s);if(!a)return!1;if(r?.session===a.session)try{r.send("cancel",{id:s})}catch{}return n(s,{ok:!1,error:`The browser did not answer within ${Math.round(o/1e3)} s — the user may not have answered a confirmation. Ask them.`,code:"timeout"})},sessionOf:()=>r?.session||null}}function y(e){return e?.connected?`You can use the user's own ${{chrome:"Chrome",edge:"Edge",firefox:"Firefox",brave:"Brave",opera:"Opera",chromium:"Chromium"}[e.browser?.kind]||"web browser"} (where they are signed in) through the \`${e.spec?.name||"page"}\` tool. Start a task with {"action":"open_tab","args":{"url":"…"}}: it opens in its own tab, and every later action acts on that tab. Read with read_page, find fields with inspect_page, fill with fill_form — never guess a value the user has not given; ask them. The browser asks the user before anything is submitted, paid or booked, and hands them any human-verification check; if an action is declined or a check is waiting, stop and tell the user.`:""}export{g as BROWSER_KINDS,l as BROWSER_RELAY,y as browserRelaySystem,b as createBrowserRelay,k as validateBrowserAnnounce,w as validateBrowserCall,x as validateBrowserResult};
1
+ const l=Object.freeze({maxPending:8,callMs:12e4,maxCallMs:6e5,maxArgsChars:64e3,maxResultChars:1e6,maxSpecChars:64e3,maxActionsChars:96e3,maxSystemChars:16e3,maxTaskChars:200}),g=Object.freeze(["chrome","edge","firefox","brave","opera","chromium","other"]),h=/^[a-z][a-z0-9_]{0,63}$/,f=e=>e!=null&&typeof e=="object"&&!Array.isArray(e),u=e=>{try{return JSON.stringify(e??null).length}catch{return 1/0}};function w(e){if(!f(e))return{ok:!1,error:"body must be a JSON object"};const r=String(e.action||"");if(!h.test(r))return{ok:!1,error:"action must be a page action name (e.g. open_tab, read_page, fill_form)"};const t=e.args==null?{}:e.args;if(!f(t))return{ok:!1,error:"args must be an object"};if(u(t)>l.maxArgsChars)return{ok:!1,error:"args too large"};const n=String(e.task||"").replace(/\s+/g," ").trim().slice(0,l.maxTaskChars),i=Number(e.timeoutMs),s=Number.isFinite(i)&&i>0?Math.min(i,l.maxCallMs):l.callMs;return{ok:!0,call:{action:r,args:t,task:n,timeoutMs:s}}}function k(e){if(!f(e))return{ok:!1,error:"body must be a JSON object"};const r=String(e.session||"");if(!r)return{ok:!1,error:"session required"};const t=g.includes(e.browser?.kind)?e.browser.kind:"other",n=String(e.browser?.version||"").slice(0,40),i=e.spec;if(!f(i)||typeof i.name!="string"||!f(i.parameters))return{ok:!1,error:"spec must be a tool spec { name, description, parameters }"};if(u(i)>l.maxSpecChars)return{ok:!1,error:"spec too large"};const s=String(e.system||"").slice(0,l.maxSystemChars),o=String(e.extension||"").slice(0,40);let a=[];if(e.actions!=null){if(!Array.isArray(e.actions)||!e.actions.every(c=>f(c)&&typeof c.name=="string"&&h.test(c.name)))return{ok:!1,error:"actions must be tool specs { name, description, parameters }"};if(u(e.actions)>l.maxActionsChars)return{ok:!1,error:"actions too large"};a=e.actions}return{ok:!0,announce:{session:r,browser:{kind:t,version:n},spec:i,system:s,extension:o,actions:a}}}function x(e){if(!f(e))return{ok:!1,error:"body must be a JSON object"};const r=String(e.session||""),t=String(e.id||"");if(!r||!t)return{ok:!1,error:"session and id required"};const n=e.result;return typeof n=="string"||f(n)&&typeof n.text=="string"&&(n.image==null||typeof n.image=="string")?u(n)>l.maxResultChars?{ok:!1,error:"result too large"}:{ok:!0,answer:{session:r,id:t,result:n}}:{ok:!1,error:"result must be a string or { text, image? }"}}function b({newId:e}={}){if(typeof e!="function")throw new Error("createBrowserRelay: newId required");let r=null;const t=new Map,n=(s,o)=>{const a=t.get(s);return a?(t.delete(s),a.resolve(o),!0):!1},i=(s,o,a)=>{for(const[c,m]of t)m.session===s&&n(c,{ok:!1,error:o,code:a})};return{connect(s){if(typeof s!="function")throw new Error("connect: send required");if(r){const o=r;i(o.session,"The browser reconnected; the call was lost. Try it again.","reconnected");try{o.send("replaced",{})}catch{}}return r={session:e(),send:s,offer:null},r.session},announce(s){return!r||s?.session!==r.session?!1:(r.offer={browser:s.browser,spec:s.spec,system:s.system,extension:s.extension||"",actions:Array.isArray(s.actions)?s.actions:[]},!0)},disconnect(s){return!r||r.session!==s?!1:(i(s,"The browser disconnected (the Chap panel was closed). Ask the user to open it and try again.","disconnected"),r=null,!0)},status(){return r?.offer?{connected:!0,browser:r.offer.browser,extension:r.offer.extension,spec:r.offer.spec,system:r.offer.system,actions:r.offer.actions,pending:t.size}:{connected:!1,pending:t.size,...r?{waiting:!0}:{}}},call({action:s,args:o={},task:a=""}){if(!r?.offer)return{id:null,done:Promise.resolve({ok:!1,error:"No browser is connected. Ask the user to open the Chap side panel in their browser (Chrome, Edge or Firefox) and try again.",code:"not_connected"})};if(t.size>=l.maxPending)return{id:null,done:Promise.resolve({ok:!1,error:"The browser is busy with other calls; wait for them to finish.",code:"busy"})};const c=e(),m=r.session,p=new Promise(d=>t.set(c,{session:m,resolve:d}));try{r.send("call",{id:c,action:s,args:o,task:a})}catch{n(c,{ok:!1,error:"The browser stream closed while sending the call.",code:"disconnected"})}return{id:c,done:p}},answer({session:s,id:o,result:a}){const c=t.get(o);return!c||c.session!==s?!1:n(o,{ok:!0,result:a})},expire(s,o=l.callMs){const a=t.get(s);if(!a)return!1;if(r?.session===a.session)try{r.send("cancel",{id:s})}catch{}return n(s,{ok:!1,error:`The browser did not answer within ${Math.round(o/1e3)} s — the user may not have answered a confirmation. Ask them.`,code:"timeout"})},sessionOf:()=>r?.session||null}}function y(e){return e?.connected?`You can use the user's own ${{chrome:"Chrome",edge:"Edge",firefox:"Firefox",brave:"Brave",opera:"Opera",chromium:"Chromium"}[e.browser?.kind]||"web browser"} (where they are signed in) through the \`${e.spec?.name||"page"}\` tool. Start a task with {"action":"open_tab","args":{"url":"…"}}: it opens in its own tab, and every later action acts on that tab. Read with read_page, find fields with inspect_page, fill with fill_form — never guess a value the user has not given; ask them. The browser asks the user before anything is submitted, paid or booked, and hands them any human-verification check; if an action is declined or a check is waiting, stop and tell the user.`:""}export{g as BROWSER_KINDS,l as BROWSER_RELAY,y as browserRelaySystem,b as createBrowserRelay,k as validateBrowserAnnounce,w as validateBrowserCall,x as validateBrowserResult};
@@ -1 +1 @@
1
- import{CAPABILITIES as r}from"./capability-endpoints.js";const i=Object.freeze({chat:[{id:"chat",label:"Chat",what:"answers and drafts in the thread"},{id:"notes",label:"Notes",what:"the co-writer and the note actions"},{id:"meetings",label:"Meetings",what:"the running summary, insights and monitors"},{id:"jobs",label:"Jobs & teams",what:"scheduled and triggered work, team runs"}],stt:[{id:"dictation",label:"Dictation",what:"speaking into a composer"},{id:"voice",label:"Voice conversation",what:"talking with the assistant"},{id:"meetings",label:"Meetings",what:"the audio scribe — what is playing and the room"}],tts:[{id:"read-aloud",label:"Read aloud",what:"a reply spoken on request"},{id:"voice",label:"Voice conversation",what:"the assistant’s replies spoken"}],detect:[{id:"redaction",label:"Redaction",what:"names, places and secrets replaced before a model sees them"},{id:"fast-path",label:"Fast path",what:"an extraction asked in chat answered without a language model"}],decide:[{id:"routing",label:"Model routing",what:"which model a message goes to, when the decision model is set to route Auto (Routing › Decision model routes Auto)"},{id:"fast-path",label:"Fast path",what:"a classification asked in chat answered without a language model"},{id:"tools",label:"Tools for the model",what:"a turn’s decide tool, when the model asks for a typed judgement"},{id:"mcp",label:"MCP tool choice",what:"which server’s tools a message needs"},{id:"speaker-names",label:"Speaker naming",what:"“speaker 2 must be Priya” read from a chat message"},{id:"teams",label:"Teams",what:"the assignments a team run makes"}],rerank:[{id:"search",label:"Search",what:"history and web results ordered by relevance"},{id:"tools",label:"Tools for the model",what:"a turn’s rerank tool"},{id:"mcp",label:"MCP tool choice",what:"the tools a lookup (find) returns from your MCP servers, ordered by meaning as well as words"},{id:"notes",label:"Notes research",what:"sources ordered for a plan note"}],embed:[{id:"search",label:"Semantic search",what:"meaning-based retrieval over notes, chats and meetings"}],search:[{id:"chat",label:"Chat",what:"web search in a turn"},{id:"notes",label:"Notes research",what:"sources for a plan note"}],read:[{id:"chat",label:"Chat",what:"a page read for a turn"},{id:"notes",label:"Notes research",what:"sources read for a note"}],extract:[{id:"attachments",label:"Attachments",what:"documents attached by reference, read by page"}],s2s:[{id:"voice",label:"Voice conversation",what:"speech in, speech out, no text in between"}]});for(const e of r)if(!i[e])throw new Error(`capability-uses: ${e} has no uses listed`);function l(e,a,t){return e?.ui?.capabilityUses?.[a]?.[t]!==!1}function h(e,a){return(i[a]||[]).map(t=>({...t,on:l(e,a,t.id)}))}function c(e,a,t,n){const s={...e?.ui?.capabilityUses||{}},o={...s[a]||{}};return n?delete o[t]:o[t]=!1,Object.keys(o).length?s[a]=o:delete s[a],{ui:{capabilityUses:s}}}export{i as CAPABILITY_USES,c as setUse,l as useAllowed,h as usesOf};
1
+ import{CAPABILITIES as i}from"./capability-endpoints.js";const n=Object.freeze({chat:[{id:"chat",label:"Chat",what:"answers and drafts in the thread"},{id:"notes",label:"Notes",what:"the co-writer and the note actions"},{id:"meetings",label:"Meetings",what:"the running summary, insights and monitors"},{id:"jobs",label:"Jobs & teams",what:"scheduled and triggered work, team runs"}],stt:[{id:"dictation",label:"Dictation",what:"speaking into a composer"},{id:"voice",label:"Voice conversation",what:"talking with the assistant"},{id:"meetings",label:"Meetings",what:"the audio scribe — what is playing and the room"}],tts:[{id:"read-aloud",label:"Read aloud",what:"a reply spoken on request"},{id:"voice",label:"Voice conversation",what:"the assistant’s replies spoken"}],detect:[{id:"redaction",label:"Redaction",what:"names, places and secrets replaced before a model sees them"},{id:"fast-path",label:"Fast path",what:"an extraction asked in chat answered without a language model"}],decide:[{id:"routing",label:"Model routing",what:"which model a message goes to, when the decision model is set to route Auto (Routing › Decision model routes Auto)"},{id:"fast-path",label:"Fast path",what:"a classification asked in chat answered without a language model"},{id:"lookups",label:"What to look up",what:"whether a message needs the web, the weather or your own data — and what to search — before a small model answers"},{id:"tools",label:"Tools for the model",what:"a turn’s decide tool, when the model asks for a typed judgement"},{id:"mcp",label:"MCP tool choice",what:"which server’s tools a message needs"},{id:"speaker-names",label:"Speaker naming",what:"“speaker 2 must be Priya” read from a chat message"},{id:"teams",label:"Teams",what:"the assignments a team run makes"}],rerank:[{id:"search",label:"Search",what:"history and web results ordered by relevance"},{id:"tools",label:"Tools for the model",what:"a turn’s rerank tool"},{id:"mcp",label:"MCP tool choice",what:"the tools a lookup (find) returns from your MCP servers, ordered by meaning as well as words"},{id:"notes",label:"Notes research",what:"sources ordered for a plan note"}],embed:[{id:"search",label:"Semantic search",what:"meaning-based retrieval over notes, chats and meetings"}],search:[{id:"chat",label:"Chat",what:"web search in a turn"},{id:"notes",label:"Notes research",what:"sources for a plan note"}],read:[{id:"chat",label:"Chat",what:"a page read for a turn"},{id:"notes",label:"Notes research",what:"sources read for a note"}],extract:[{id:"attachments",label:"Attachments",what:"documents attached by reference, read by page"}],s2s:[{id:"voice",label:"Voice conversation",what:"speech in, speech out, no text in between"}]});for(const e of i)if(!n[e])throw new Error(`capability-uses: ${e} has no uses listed`);function l(e,a,t){return e?.ui?.capabilityUses?.[a]?.[t]!==!1}function h(e,a){return(n[a]||[]).map(t=>({...t,on:l(e,a,t.id)}))}function c(e,a,t,r){const s={...e?.ui?.capabilityUses||{}},o={...s[a]||{}};return r?delete o[t]:o[t]=!1,Object.keys(o).length?s[a]=o:delete s[a],{ui:{capabilityUses:s}}}export{n as CAPABILITY_USES,c as setUse,l as useAllowed,h as usesOf};
package/client-prefs.js CHANGED
@@ -1 +1 @@
1
- const c=Object.freeze([{id:"mcpServers",label:"MCP tool servers",path:["mcpServers"],kind:"array"},{id:"skills",label:"Skills",path:["skills"],kind:"array"},{id:"skillDirs",label:"Skill folders",path:["ui","skillDirs"],kind:"array"},{id:"recipes",label:"Recipes",path:["recipes"],kind:"array"},{id:"teams",label:"Teams",path:["teams"],kind:"array"},{id:"agents",label:"Agents",path:["agentPool"],kind:"array"},{id:"connections",label:"Connections",path:["connections"],kind:"array"},{id:"projects",label:"Projects",path:["projects"],kind:"array"},{id:"webSearch",label:"Web search",path:["ui","webSearch"],kind:"object"},{id:"tools",label:"Tools",path:null,kind:"object",keys:["mcpToolsMode","maxToolsPerTurn","maxToolRoundsPerTurn","historyTools","historyContextMode","dataDispatch","toolResultMaxChars"]},{id:"endpoints",label:"Models",path:["endpoints"],kind:"array"},{id:"agentTools",label:"Coding Agents",path:null,kind:"object",rootKeys:["agents","removedBuiltinAgents"]},{id:"freeSlots",label:"Free plan picks",path:null,kind:"object",rootKeys:["freeEndpointId","freeAgentId"]},{id:"routing",label:"Model routing",path:["ui","routing"],kind:"object"},{id:"capabilityUses",label:"Where models may be used",path:["ui","capabilityUses"],kind:"object"},{id:"general",label:"General",path:null,kind:"object",keys:["theme","language","sendOnEnter","streamResponses","autoAttachActiveTab","autocomplete","settingsOpen"]},{id:"identity",label:"Identity",path:null,kind:"object",rootKeys:["selfName"]},{id:"suggestions",label:"Smart suggestions",path:["ui","suggestions"],kind:"object"},{id:"topics",label:"Topic extraction",path:["ui","topicExtraction"],kind:"object"},{id:"memory",label:"Memory",path:["ui","memory"],kind:"object"},{id:"notes",label:"Notes",path:["ui","notes"],kind:"object"},{id:"speech",label:"Speech",path:null,kind:"object",keys:["dictation","capture","scribeLive"]},{id:"warmSearch",label:"Gateway search index",path:["ui","warmSearch"],kind:"object"},{id:"recall",label:"Search & indexing",path:["ui","recall"],kind:"object"},{id:"voice",label:"Voice",path:["ui","voice"],kind:"object"},{id:"watch",label:"Watch",path:["ui","watch"],kind:"object"},{id:"meetings",label:"Meetings",path:null,kind:"object",keys:["meetingWindowMin","liveNotesIntervalMin","alertSound","meetingSummaryStyle"]},{id:"monitors",label:"Live monitors",path:["ui","monitors"],kind:"object"},{id:"redaction",label:"Redaction (client-side)",path:["ui","piiRedaction"],kind:"object"},{id:"internalSites",label:"Internal sites",path:["privacy"],kind:"object"},{id:"pageActions",label:"Act on page",path:null,kind:"object",browserOnly:!0,keys:["pageActions","pageActionsCdp","pageActionsDevJs","pageActionConfirm","pageSites"]},{id:"webllm",label:"In-browser model",path:null,kind:"object",browserOnly:!0,keys:["webllmBackground"],rootKeys:["webllmCustomModels"]}]),f=Object.freeze(c.map(t=>t.id)),m=Object.freeze(c.filter(t=>!t.browserOnly).map(t=>t.id));function g(t){return c.find(o=>o.id===t)}const s=t=>t===void 0?void 0:JSON.parse(JSON.stringify(t));function h(t,o){let e=t;for(const i of o){if(!e||typeof e!="object")return;e=e[i]}return e}function k(t,o,e){let i=t;for(let a=0;a<o.length-1;a+=1){const r=o[a];(!i[r]||typeof i[r]!="object")&&(i[r]={}),i=i[r]}i[o[o.length-1]]=e}function y(t,o){const e=c.find(n=>n.id===o);if(!e||!t)return;if(e.path)return s(h(t,e.path));const i=t.ui||{},a={};let r=!1;for(const n of e.keys||[])i[n]!==void 0&&(a[n]=s(i[n]),r=!0);for(const n of e.rootKeys||[])t[n]!==void 0&&(a[n]=s(t[n]),r=!0);return r?a:void 0}function j(t){const o={};for(const e of c){const i=y(t,e.id);i!==void 0&&(o[e.id]=i)}return o}function S(t,o){const e=s(t||{})||{};for(const[i,a]of Object.entries(o||{})){const r=c.find(n=>n.id===i);if(!(!r||a===void 0)){if(r.path){k(e,r.path,s(a));continue}(!e.ui||typeof e.ui!="object")&&(e.ui={});for(const n of r.keys||[])a&&a[n]!==void 0&&(e.ui[n]=s(a[n]));for(const n of r.rootKeys||[])a&&a[n]!==void 0&&(e[n]=s(a[n]))}}return e}function b(t){const o=e=>Array.isArray(e)?e.map(o):e&&typeof e=="object"?Object.fromEntries(Object.keys(e).sort().map(i=>[i,o(e[i])])):e;try{return JSON.stringify(o(t))}catch{return String(t)}}function O(t={},o={}){const e={},i=[],a=[],r=new Set([...Object.keys(t||{}),...Object.keys(o||{})]);for(const n of r){const l=t?.[n],d=o?.[n],u=Number(l?.updatedAt)||0,p=Number(d?.updatedAt)||0;if(d&&(!l||p>u)){e[n]={value:s(d.value),updatedAt:p},(!l||b(l.value)!==b(d.value))&&i.push(n);continue}l&&(e[n]={value:s(l.value),updatedAt:u},(!d||u>p)&&a.push(n))}return{merged:e,fromRemote:i,fromLocal:a}}function x(t,o={},{now:e=Date.now()}={}){const i={};for(const[a,r]of Object.entries(t||{})){if(!f.includes(a))continue;const n=o?.[a];n&&n.hash===b(r)||(i[a]={value:s(r),updatedAt:e})}return i}export{m as DESKTOP_SECTION_IDS,c as PREF_SECTIONS,f as PREF_SECTION_IDS,S as applySections,x as changedSections,O as mergeStamped,j as pickSections,b as sectionHash,g as sectionSpec,y as sectionValue};
1
+ const c=Object.freeze([{id:"mcpServers",label:"MCP tool servers",path:["mcpServers"],kind:"array"},{id:"skills",label:"Skills",path:["skills"],kind:"array"},{id:"skillDirs",label:"Skill folders",path:["ui","skillDirs"],kind:"array"},{id:"recipes",label:"Recipes",path:["recipes"],kind:"array"},{id:"teams",label:"Teams",path:["teams"],kind:"array"},{id:"agents",label:"Agents",path:["agentPool"],kind:"array"},{id:"connections",label:"Connections",path:["connections"],kind:"array"},{id:"projects",label:"Projects",path:["projects"],kind:"array"},{id:"webSearch",label:"Web search",path:["ui","webSearch"],kind:"object"},{id:"tools",label:"Tools",path:null,kind:"object",keys:["mcpToolsMode","maxToolsPerTurn","maxToolRoundsPerTurn","historyTools","historyContextMode","dataDispatch","toolResultMaxChars"]},{id:"endpoints",label:"Models",path:["endpoints"],kind:"array"},{id:"agentTools",label:"Coding Agents",path:null,kind:"object",rootKeys:["agents","removedBuiltinAgents"]},{id:"freeSlots",label:"Free plan picks",path:null,kind:"object",rootKeys:["freeEndpointId","freeAgentId"]},{id:"routing",label:"Model routing",path:["ui","routing"],kind:"object"},{id:"capabilityUses",label:"Where models may be used",path:["ui","capabilityUses"],kind:"object"},{id:"general",label:"General",path:null,kind:"object",keys:["theme","language","sendOnEnter","streamResponses","autoAttachActiveTab","autocomplete","settingsOpen"]},{id:"identity",label:"Identity",path:null,kind:"object",rootKeys:["selfName"]},{id:"suggestions",label:"Smart suggestions",path:["ui","suggestions"],kind:"object"},{id:"topics",label:"Topic extraction",path:["ui","topicExtraction"],kind:"object"},{id:"memory",label:"Memory",path:["ui","memory"],kind:"object"},{id:"notes",label:"Notes",path:["ui","notes"],kind:"object"},{id:"speech",label:"Speech",path:null,kind:"object",keys:["dictation","capture","scribeLive"]},{id:"warmSearch",label:"Gateway search index",path:["ui","warmSearch"],kind:"object"},{id:"recall",label:"Search & indexing",path:["ui","recall"],kind:"object"},{id:"voice",label:"Voice",path:["ui","voice"],kind:"object"},{id:"watch",label:"Watch",path:["ui","watch"],kind:"object"},{id:"meetings",label:"Meetings",path:null,kind:"object",keys:["meetingWindowMin","liveNotesIntervalMin","alertSound","meetingSummaryStyle","meetingAutoOpen"]},{id:"monitors",label:"Live monitors",path:["ui","monitors"],kind:"object"},{id:"redaction",label:"Redaction (client-side)",path:["ui","piiRedaction"],kind:"object"},{id:"internalSites",label:"Internal sites",path:["privacy"],kind:"object"},{id:"pageActions",label:"Act on page",path:null,kind:"object",browserOnly:!0,keys:["pageActions","pageActionsCdp","pageActionsDevJs","pageActionConfirm","pageSites"]},{id:"webllm",label:"In-browser model",path:null,kind:"object",browserOnly:!0,keys:["webllmBackground"],rootKeys:["webllmCustomModels"]}]),f=Object.freeze(c.map(t=>t.id)),m=Object.freeze(c.filter(t=>!t.browserOnly).map(t=>t.id));function g(t){return c.find(o=>o.id===t)}const s=t=>t===void 0?void 0:JSON.parse(JSON.stringify(t));function h(t,o){let e=t;for(const i of o){if(!e||typeof e!="object")return;e=e[i]}return e}function k(t,o,e){let i=t;for(let a=0;a<o.length-1;a+=1){const r=o[a];(!i[r]||typeof i[r]!="object")&&(i[r]={}),i=i[r]}i[o[o.length-1]]=e}function y(t,o){const e=c.find(n=>n.id===o);if(!e||!t)return;if(e.path)return s(h(t,e.path));const i=t.ui||{},a={};let r=!1;for(const n of e.keys||[])i[n]!==void 0&&(a[n]=s(i[n]),r=!0);for(const n of e.rootKeys||[])t[n]!==void 0&&(a[n]=s(t[n]),r=!0);return r?a:void 0}function j(t){const o={};for(const e of c){const i=y(t,e.id);i!==void 0&&(o[e.id]=i)}return o}function S(t,o){const e=s(t||{})||{};for(const[i,a]of Object.entries(o||{})){const r=c.find(n=>n.id===i);if(!(!r||a===void 0)){if(r.path){k(e,r.path,s(a));continue}(!e.ui||typeof e.ui!="object")&&(e.ui={});for(const n of r.keys||[])a&&a[n]!==void 0&&(e.ui[n]=s(a[n]));for(const n of r.rootKeys||[])a&&a[n]!==void 0&&(e[n]=s(a[n]))}}return e}function b(t){const o=e=>Array.isArray(e)?e.map(o):e&&typeof e=="object"?Object.fromEntries(Object.keys(e).sort().map(i=>[i,o(e[i])])):e;try{return JSON.stringify(o(t))}catch{return String(t)}}function O(t={},o={}){const e={},i=[],a=[],r=new Set([...Object.keys(t||{}),...Object.keys(o||{})]);for(const n of r){const l=t?.[n],d=o?.[n],u=Number(l?.updatedAt)||0,p=Number(d?.updatedAt)||0;if(d&&(!l||p>u)){e[n]={value:s(d.value),updatedAt:p},(!l||b(l.value)!==b(d.value))&&i.push(n);continue}l&&(e[n]={value:s(l.value),updatedAt:u},(!d||u>p)&&a.push(n))}return{merged:e,fromRemote:i,fromLocal:a}}function A(t,o={},{now:e=Date.now()}={}){const i={};for(const[a,r]of Object.entries(t||{})){if(!f.includes(a))continue;const n=o?.[a];n&&n.hash===b(r)||(i[a]={value:s(r),updatedAt:e})}return i}export{m as DESKTOP_SECTION_IDS,c as PREF_SECTIONS,f as PREF_SECTION_IDS,S as applySections,A as changedSections,O as mergeStamped,j as pickSections,b as sectionHash,g as sectionSpec,y as sectionValue};
package/clock.js ADDED
@@ -0,0 +1 @@
1
+ const i=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],s=["January","February","March","April","May","June","July","August","September","October","November","December"];function y(t=Date.now()){try{const n=-new Date(t).getTimezoneOffset();return Number.isFinite(n)?n:0}catch{return 0}}function a(t,n){const e=Number.isFinite(Number(n))?Number(n):0,r=new Date(Number(t)+e*6e4);return{weekday:i[r.getUTCDay()],month:s[r.getUTCMonth()],day:r.getUTCDate(),year:r.getUTCFullYear(),hour:r.getUTCHours(),minute:r.getUTCMinutes()}}function o({now:t=Date.now(),offsetMinutes:n=0}={}){const e=a(t,n);return`${e.weekday}, ${e.month} ${e.day}, ${e.year}`}function u({now:t=Date.now(),offsetMinutes:n=0}={}){const e=a(t,n);return`${e.hour%12||12}:${String(e.minute).padStart(2,"0")} ${e.hour<12?"AM":"PM"}`}function d(t={}){return`Today is ${o(t)}. Treat this as the current date.`}const c=/^\s*(?:(?:hey|hi|ok(?:ay)?|so)[,\s]+)?(?:(?:what(?:'s|’s| is)?|tell me) (?:the )?(?:(?:current|local) )?(?:time|date|day)(?: (?:is it|it is|today|now|right now|here))*|what time is it(?: now| right now| here)?|(?:current |local )?time(?: now| right now| please)?|(?:today'?s|today’s|the) date|what day(?: of the week)? is (?:it|today)|(?:what is |what's |what’s )?today'?s? date|date today)\s*[?!.]*\s*$/i;function h(t){return c.test(String(t||""))}function m(t={}){return`[Chap] It is ${u(t)} on ${o(t)}, the person's local time (from the device's clock).`}export{o as localDate,u as localTime,y as runtimeOffsetMinutes,h as timeAsk,m as timeHint,d as todayLine};
package/compaction.js CHANGED
@@ -1,11 +1,11 @@
1
- import{keepRecentFor as m}from"./context-window.js";const h="You compress a conversation into a compact but COMPLETE summary for continuation. Preserve: the user’s goals, key facts, decisions made, current task/automation state, open questions, and specifics needed to keep going. Terse bullet points. No preamble.",f=4e3;function c(n=[]){return(Array.isArray(n)?n:[]).filter(t=>t&&!t.pending&&(t.role==="user"||t.role==="assistant")&&(t.content||t.attachments?.length))}function y({messages:n=[],keepRecent:t=4,budget:e=0,tokensOf:r=null}={}){const o=c(n);let i=Math.max(1,Math.floor(Number(t)||4));if(e>0&&typeof r=="function")for(;i>1&&o.slice(o.length-i).reduce((a,p)=>a+(r(p)||0),0)>e;)i-=1;if(o.length<=i+1)return null;const s=o.slice(0,o.length-i),l=o.slice(o.length-i),u=s.map(a=>`${a.role==="user"?"User":"Assistant"}: ${String(a.content||"").slice(0,f)}`).join(`
1
+ import{keepRecentFor as m}from"./context-window.js";const g="You compress a conversation into a compact but COMPLETE summary for continuation. Preserve: the user’s goals, key facts, decisions made, current task/automation state, open questions, and specifics needed to keep going. Terse bullet points. No preamble.",f=4e3;function a(e=[]){return(Array.isArray(e)?e:[]).filter(t=>t&&!t.pending&&(t.role==="user"||t.role==="assistant")&&(t.content||t.attachments?.length))}function y({messages:e=[],keepRecent:t=4,budget:n=0,tokensOf:o=null}={}){const r=a(e);let i=Math.max(1,Math.floor(Number(t)||4));if(n>0&&typeof o=="function")for(;i>1&&r.slice(r.length-i).reduce((c,p)=>c+(o(p)||0),0)>n;)i-=1;if(r.length<=i+1)return null;const s=r.slice(0,r.length-i),l=r.slice(r.length-i),u=s.map(c=>`${c.role==="user"?"User":"Assistant"}: ${String(c.content||"").slice(0,f)}`).join(`
2
2
 
3
- `);return{fold:s,keep:l,uptoId:s[s.length-1].id,transcript:u}}function g({transcript:n="",previousSummary:t=""}={}){return`${t?`Earlier summary to fold in:
3
+ `);return{fold:s,keep:l,uptoId:s[s.length-1].id,transcript:u}}function x({transcript:e="",previousSummary:t=""}={}){return`${t?`Earlier summary to fold in:
4
4
  ${t}
5
5
 
6
6
  `:""}Summarize the conversation so far:
7
7
 
8
- ${n}`}function x({summary:n,uptoId:t,now:e=Date.now()}={}){return{summary:String(n||"").trim(),uptoId:t,ts:e}}function S(n=[],t=null){const e=c(n);if(!t?.uptoId)return e;const r=e.findIndex(o=>o.id===t.uptoId);return r>=0?e.slice(r+1):e}function $(n="",t=null){const e=String(t?.summary||"").trim();return e?`${n?`${n}
8
+ ${e}`}function S({summary:e,uptoId:t,now:n=Date.now()}={}){return{summary:String(e||"").trim(),uptoId:t,ts:n}}function A(e=[],t=null){const n=a(e);if(!t?.uptoId)return n;const o=n.findIndex(r=>r.id===t.uptoId);return o>=0?n.slice(o+1):n}function E(e="",t=null){const n=String(t?.summary||"").trim();return n?`${e?`${e}
9
9
 
10
10
  `:""}[Summary of the earlier part of this conversation — continue seamlessly; do not mention this summary]
11
- ${e}`:n||""}export{h as COMPACTION_SYSTEM,c as compactable,g as compactionPrompt,x as compactionRecord,m as keepRecentFor,S as messagesAfter,y as planCompaction,$ as systemWithSummary};
11
+ ${n}`:e||""}const d=36e4;function k(e=[],{maxChars:t=d}={}){const n=Array.isArray(e)?e:[];let o=0,r=n.length;for(;r>0;){const i=String(n[r-1]?.content??"").length+16;if(o+i>t&&r<n.length)break;o+=i,r-=1}return{kept:n.slice(r),elided:r}}export{g as COMPACTION_SYSTEM,d as SEED_MAX_CHARS,a as compactable,x as compactionPrompt,S as compactionRecord,m as keepRecentFor,A as messagesAfter,y as planCompaction,k as seedWithin,E as systemWithSummary};
@@ -0,0 +1,2 @@
1
+ import{buildIndex as R,bm25Search as j}from"./text-index.js";const C=2e3,L=.3;async function k({messages:r=[],budget:t=0,tokensOf:o,keepRecent:c=1,query:i=null,rank:g=null}={}){const s=Array.isArray(r)?r.filter(Boolean):[];if(!s.length)return{messages:[],recalled:0,left:0};const m=s[s.length-1],a=s.slice(0,-1),p=e=>e.reduce((n,w)=>n+(Number(o?.(w))||0),0);if(p(a)<=t)return{messages:s,recalled:0,left:0};const l=O(a),u=new Set;let x=Math.max(0,Number(t)||0);const d=e=>{const n=p(l[e]);return n>x?!1:(u.add(e),x-=n,!0)},M=Math.max(0,Math.floor(Number(c)||0));for(let e=l.length-1;e>=Math.max(0,l.length-M)&&d(e);e--);const A=l.map((e,n)=>({id:String(n),text:h(e).slice(0,C)})).filter(e=>!u.has(Number(e.id))&&e.text.trim());let f=await N(i??h([m]),A,g);!f.length&&i==null&&(f=await N(h([B(a)]),A,g));const S=(f[0]?.score||0)*L,b=[];for(const{id:e}of f.filter(n=>n.score>=S)){const n=Number(e);d(n)&&b.push(n)}const y=l.flatMap((e,n)=>u.has(n)?e:[]);return{messages:[...y,m],recalled:b.reduce((e,n)=>e+l[n].length,0),left:a.length-y.length}}function O(r){const t=[];for(const o of r)o.role==="user"||!t.length?t.push([o]):t[t.length-1].push(o);return t}function B(r){for(let t=r.length-1;t>=0;t--)if(r[t]?.role==="user")return r[t];return null}function h(r){return r.filter(Boolean).map(t=>[typeof t.content=="string"?t.content:Array.isArray(t.content)?t.content.map(o=>o?.text||"").join(" "):"",...(t.attachments||[]).map(o=>o?.title||"")].join(" ")).join(`
2
+ `)}async function N(r,t,o){if(!t.length||!String(r||"").trim())return[];if(typeof o=="function")try{const c=await o(r,t);if(Array.isArray(c)&&c.length)return c.filter(i=>i&&Number(i.score)>0)}catch{}return j(R(t),r)}export{L as RECALL_FLOOR,k as selectContext};
package/context-window.js CHANGED
@@ -1 +1 @@
1
- const l=[[/gpt-4\.1/,1e6],[/gpt-5|o3|o4|o1/,2e5],[/gpt-4o|gpt-4-turbo/,128e3],[/claude-(3|4|5|opus|sonnet|haiku|fable)/,2e5],[/gemini-(1\.5|2|2\.5|3)/,1e6],[/gemini/,1e6],[/deepseek/,128e3],[/mistral-large|mixtral|codestral/,128e3],[/grok/,128e3],[/llama-3\.[1-3]|llama-4/,128e3]];function a(t={},n=null){const e=String(t.id||""),i=String(t.model||t.id||"").toLowerCase(),u=n&&(n[d(t)]||n[i]||n[String(t.model||"")]||(t.gateway?0:n[e]));if(Number(u)>0)return Number(u);const r=Number(t.window||t.contextLength||t.contextWindow||0);if(r>0)return r;if(t.reach==="device"||t.kind==="webllm")return 0;for(const[o,c]of l)if(o.test(i))return c;return 0}function d(t={}){const n=String(t.id||""),e=String(t.model||"");return e?`${n}:${e}`:n}const s=.85;function f({promptTokens:t=0,floorTokens:n=0,window:e=0,reserve:i=1024,headroom:u=s}={}){const r=Number(e)||0;if(!r)return{status:"unknown",budget:0,over:0,window:0};const o=Math.max(0,Math.floor(r*u)-Math.max(0,Number(i)||0)),c=Math.max(0,Number(t)||0),m=Math.max(0,Number(n)||0);return c<=o?{status:"ok",budget:o,over:0,window:r}:m<=o?{status:"compact",budget:o,over:c-o,window:r}:{status:"too-big",budget:o,over:m-o,window:r}}function x(t=0){const n=Number(t)||0;return n?n<=8e3?2:n<=32768?4:n<=128e3?8:12:4}function w({floorTokens:t=0,reserve:n=1024,headroom:e=s}={}){const i=Math.max(0,Number(t)||0);return i?Math.ceil((i+Math.max(0,Number(n)||0))/e):0}function p(t){return/context.{0,8}(length|window|size)|context_length_exceeded|prompt is too long|too many tokens|maximum context|exceed.{0,20}context|reduce the (length|number|size)|input is too long|token limit|n_ctx|kv cache/i.test(String(t?.message||t||""))}export{s as FIT_HEADROOM,f as fitFor,p as isContextLimitError,x as keepRecentFor,w as minWindowFor,d as observedKey,a as windowOf};
1
+ const d=[[/gpt-4\.1/,1e6],[/gpt-5|o3|o4|o1/,2e5],[/gpt-4o|gpt-4-turbo/,128e3],[/claude-(3|4|5|opus|sonnet|haiku|fable)/,2e5],[/gemini-(1\.5|2|2\.5|3)/,1e6],[/gemini/,1e6],[/deepseek/,128e3],[/mistral-large|mixtral|codestral/,128e3],[/grok/,128e3],[/llama-3\.[1-3]|llama-4/,128e3]];function x(t={},n=null){const e=String(t.id||""),i=String(t.model||t.id||"").toLowerCase(),u=n&&(n[l(t)]||n[i]||n[String(t.model||"")]||(t.gateway?0:n[e]));if(Number(u)>0)return Number(u);const r=Number(t.window||t.contextLength||t.contextWindow||0);if(r>0)return r;if(t.reach==="device"||t.kind==="webllm")return 0;for(const[o,c]of d)if(o.test(i))return c;return 0}function l(t={}){const n=String(t.id||""),e=String(t.model||"");return e?`${n}:${e}`:n}const s=.85,a=8192,f=t=>Number(t)>0&&Number(t)<=a,w=2;function p({promptTokens:t=0,floorTokens:n=0,window:e=0,reserve:i=1024,headroom:u=s}={}){const r=Number(e)||0;if(!r)return{status:"unknown",budget:0,over:0,window:0};const o=Math.max(0,Math.floor(r*u)-Math.max(0,Number(i)||0)),c=Math.max(0,Number(t)||0),m=Math.max(0,Number(n)||0);return c<=o?{status:"ok",budget:o,over:0,window:r}:m<=o?{status:"compact",budget:o,over:c-o,window:r}:{status:"too-big",budget:o,over:m-o,window:r}}function _(t=0){const n=Number(t)||0;return n?n<=8e3?2:n<=32768?4:n<=128e3?8:12:4}function b({floorTokens:t=0,reserve:n=1024,headroom:e=s}={}){const i=Math.max(0,Number(t)||0);return i?Math.ceil((i+Math.max(0,Number(n)||0))/e):0}function h(t){return/context.{0,8}(length|window|size)|context_length_exceeded|prompt is too long|too many tokens|maximum context|exceed.{0,20}context|reduce the (length|number|size)|input is too long|token limit|n_ctx|kv cache|longer than .{0,80}\bwindow\b|exceed.{0,30}\bwindow\b/i.test(String(t?.message||t||""))}export{s as FIT_HEADROOM,a as SMALL_WINDOW,w as SMALL_WINDOW_ROUNDS,p as fitFor,h as isContextLimitError,f as isSmallWindow,_ as keepRecentFor,b as minWindowFor,l as observedKey,x as windowOf};
package/dialect-a2a.js CHANGED
@@ -1,3 +1,3 @@
1
- import{normalizeCard as s,cardToProfile as p,A2A_VERSION as u}from"./agent-card.js";import{defineAgentDialect as h}from"./agent-dialects.js";const a=t=>typeof t=="string"?t.trim():t==null?"":String(t).trim(),y=h({id:"a2a",label:"A2A agent card",filename:t=>`${t?.id||"agent"}.agent-card.json`,detect(t,{filename:r=""}={}){let n;try{n=JSON.parse(String(t??""))}catch{return 0}if(!n||typeof n!="object"||Array.isArray(n))return 0;const i=!!a(n.name)&&!!a(n.description),e=Array.isArray(n.supportedInterfaces)||!!a(n.url)||!!n.capabilities;return/agent-card\.json$/i.test(r)&&i?.99:i&&e&&Array.isArray(n.skills)?.9:i&&e?.6:0},parse(t,{name:r=""}={}){let n;try{n=JSON.parse(String(t??""))}catch{return{form:{},extras:{},warnings:["not JSON"]}}const i=s(n),e=[];return i.supportedInterfaces.length||e.push("this card names no endpoint, so there is nowhere to reach the agent"),e.push("a card advertises a remote agent: its engine is a placeholder until ChatPanel can call an A2A endpoint"),{form:{id:"",name:i.name||a(r),purpose:i.description,prompt:m(i),engine:{kind:"auto",policy:{prefer:"balanced"}},grants:["none"],skills:i.skills.map(o=>o.id)},extras:{card:i},warnings:e}},render(t){return`${JSON.stringify(g(t),null,2)}
1
+ import{normalizeCard as s,cardToProfile as p,A2A_VERSION as u}from"./agent-card.js";import{defineAgentDialect as h}from"./agent-dialects.js";const a=t=>typeof t=="string"?t.trim():t==null?"":String(t).trim(),y=h({id:"a2a",label:"A2A agent card",filename:t=>`${t?.id||"agent"}.agent-card.json`,detect(t,{filename:r=""}={}){let n;try{n=JSON.parse(String(t??""))}catch{return 0}if(!n||typeof n!="object"||Array.isArray(n))return 0;const i=!!a(n.name)&&!!a(n.description),e=Array.isArray(n.supportedInterfaces)||!!a(n.url)||!!n.capabilities;return/agent-card\.json$/i.test(r)&&i?.99:i&&e&&Array.isArray(n.skills)?.9:i&&e?.6:0},parse(t,{name:r=""}={}){let n;try{n=JSON.parse(String(t??""))}catch{return{form:{},extras:{},warnings:["not JSON"]}}const i=s(n),e=[];return i.supportedInterfaces.length||e.push("this card names no endpoint, so there is nowhere to reach the agent"),e.push("a card advertises a remote agent: its engine is a placeholder until Chap can call an A2A endpoint"),{form:{id:"",name:i.name||a(r),purpose:i.description,prompt:m(i),engine:{kind:"auto",policy:{prefer:"balanced"}},grants:["none"],skills:i.skills.map(o=>o.id)},extras:{card:i},warnings:e}},render(t){return`${JSON.stringify(g(t),null,2)}
2
2
  `},carries:["id","name","purpose","skills","provider","version","iconUrl","documentationUrl","tags","examples","inputModes","outputModes"],notes:{prompt:"a card is served to strangers — an agent's own instructions are never published in one",engine:"a card says where to reach an agent, never what model is behind it",grants:"what a remote agent may touch is its own operator's business, not ours to declare",tools:"a card advertises skills, not the tools behind them",denyTools:"a card advertises skills, not the tools behind them",mcpServers:"an agent's own connections are not published",permissionMode:"no equivalent — authorization is expressed with security schemes",sandboxMode:"no equivalent — how a remote agent is contained is its operator's business",maxTurns:"no equivalent in a card",effort:"no equivalent in a card",isolation:"no equivalent in a card",color:"no equivalent in a card",background:"no equivalent in a card",hooks:"no equivalent in a card",memoryScope:"no equivalent in a card",workdir:"a local path has no meaning to whoever reads the card"}});function m(t){const r=s(t),n=[];if(r.description&&n.push(r.description),r.skills.length){n.push("","What it offers:");for(const e of r.skills)n.push(`- ${e.name||e.id}${e.description?` — ${e.description}`:""}`)}const i=r.supportedInterfaces[0];return i&&n.push("",`Reached over A2A at ${i.url} (${i.protocolBinding}).`),r.provider?.organization&&n.push(`Published by ${r.provider.organization}.`),n.join(`
3
3
  `).trim()}function g(t,{interfaces:r=[],profile:n=u,skills:i=[]}={}){const e=t||{},o=e.dialectExtras?.a2a?.card,c=i.length?i:(e.skills||[]).map(l=>f(l,e)),d=s({...o||{},name:e.name||e.id||"",description:e.purpose||"",version:e.version||o?.version||"0.1.0",...e.provider?{provider:e.provider}:{},...e.iconUrl?{iconUrl:e.iconUrl}:{},...e.documentationUrl?{documentationUrl:e.documentationUrl}:{},supportedInterfaces:r.length?r:o?.supportedInterfaces||[],capabilities:{streaming:!0,pushNotifications:!1,...o?.capabilities||{}},defaultInputModes:e.inputModes?.length?e.inputModes:o?.defaultInputModes,defaultOutputModes:e.outputModes?.length?e.outputModes:o?.defaultOutputModes,skills:c});return delete d.signatures,p(d,n)}function f(t,r){const n=String(t||"").trim();return{id:n,name:n,description:`${n}, as performed by ${r?.name||r?.id||"this agent"}`,tags:r?.tags?.length?[...r.tags]:[]}}export{y as a2aDialect,m as briefFromCard,g as cardFromAgent};
package/dialect-claude.js CHANGED
@@ -1,3 +1,3 @@
1
- import{parseFrontmatter as p,renderFrontmatter as k}from"./frontmatter.js";import{defineAgentDialect as w,grantsFromTools as S,toolsFromGrants as b,toNameList as d}from"./agent-dialects.js";const T=Object.freeze(["name","description","tools","disallowedTools","model","permissionMode","maxTurns","skills","mcpServers","hooks","memory","background","omitClaudeMd","effort","isolation","color","initialPrompt","experimental"]),x=Object.freeze(["tools","disallowedTools","model","permissionMode","maxTurns","isolation","color","hooks","initialPrompt"]),m=t=>typeof t=="string"?t.trim():t==null?"":String(t).trim(),A=w({id:"claude",label:"Claude Code",filename:t=>`${t?.id||"agent"}.md`,detect(t,{filename:o=""}={}){const{meta:e,body:n}=p(t);if(!e.name&&!e.description)return 0;const i=/(^|\/)agents\//.test(o)&&/\.md$/i.test(o),r=x.some(s=>e[s]!==void 0);return/(^|\/)SKILL\.md$/i.test(o)||!i&&/(^|\/)skills\//.test(o)?0:i&&r?.95:i?.8:r?.7:n.trim()?.35:.2},parse(t,{name:o=""}={}){const{meta:e,body:n}=p(t),i=[],r=d(e.tools),{grants:s,mcpServers:c,unmapped:u}=S(r);u.length&&i.push(`tools with no ChatPanel equivalent, left ungranted rather than guessed at: ${u.join(", ")}`);const f=d(e.mcpServers),h={id:"",name:m(e.name)||m(o),purpose:m(e.description),prompt:n.trim(),engine:y(e.model),grants:s.length?s:["none"],skills:d(e.skills)},a={raw:{}};for(const[l,g]of Object.entries(e))T.includes(l)||(a.raw[l]=g);Object.keys(a.raw).length||delete a.raw,r.length&&(a.tools=r),d(e.disallowedTools).length&&(a.disallowedTools=d(e.disallowedTools)),f.length&&(a.mcpServers=f);for(const l of["permissionMode","maxTurns","memory","background","omitClaudeMd","effort","isolation","color","initialPrompt","experimental","hooks"])e[l]!==void 0&&(a[l]=e[l]);return m(e.model)&&(a.model=m(e.model)),{form:h,extras:a,warnings:i}},render(t){const o=t||{},e=o.dialectExtras?.claude||{},n={name:o.id||o.name||"agent",description:o.purpose||o.name||""},i=o.grants?.length?b(o.grants,{dialect:"claude"}):d(e.tools);i.length&&(n.tools=i),e.disallowedTools&&(n.disallowedTools=e.disallowedTools);const r=v(o,e);r&&(n.model=r),o.skills?.length&&(n.skills=[...o.skills]),e.mcpServers&&(n.mcpServers=e.mcpServers);for(const s of["permissionMode","maxTurns","memory","background","omitClaudeMd","effort","isolation","color","initialPrompt","experimental","hooks"])e[s]!==void 0&&(n[s]=e[s]);for(const[s,c]of Object.entries(e.raw||{}))n[s]===void 0&&(n[s]=c);return k(n,`
1
+ import{parseFrontmatter as p,renderFrontmatter as k}from"./frontmatter.js";import{defineAgentDialect as w,grantsFromTools as S,toolsFromGrants as b,toNameList as d}from"./agent-dialects.js";const T=Object.freeze(["name","description","tools","disallowedTools","model","permissionMode","maxTurns","skills","mcpServers","hooks","memory","background","omitClaudeMd","effort","isolation","color","initialPrompt","experimental"]),x=Object.freeze(["tools","disallowedTools","model","permissionMode","maxTurns","isolation","color","hooks","initialPrompt"]),m=t=>typeof t=="string"?t.trim():t==null?"":String(t).trim(),A=w({id:"claude",label:"Claude Code",filename:t=>`${t?.id||"agent"}.md`,detect(t,{filename:o=""}={}){const{meta:e,body:n}=p(t);if(!e.name&&!e.description)return 0;const i=/(^|\/)agents\//.test(o)&&/\.md$/i.test(o),r=x.some(s=>e[s]!==void 0);return/(^|\/)SKILL\.md$/i.test(o)||!i&&/(^|\/)skills\//.test(o)?0:i&&r?.95:i?.8:r?.7:n.trim()?.35:.2},parse(t,{name:o=""}={}){const{meta:e,body:n}=p(t),i=[],r=d(e.tools),{grants:s,mcpServers:c,unmapped:u}=S(r);u.length&&i.push(`tools with no Chap equivalent, left ungranted rather than guessed at: ${u.join(", ")}`);const f=d(e.mcpServers),h={id:"",name:m(e.name)||m(o),purpose:m(e.description),prompt:n.trim(),engine:y(e.model),grants:s.length?s:["none"],skills:d(e.skills)},a={raw:{}};for(const[l,g]of Object.entries(e))T.includes(l)||(a.raw[l]=g);Object.keys(a.raw).length||delete a.raw,r.length&&(a.tools=r),d(e.disallowedTools).length&&(a.disallowedTools=d(e.disallowedTools)),f.length&&(a.mcpServers=f);for(const l of["permissionMode","maxTurns","memory","background","omitClaudeMd","effort","isolation","color","initialPrompt","experimental","hooks"])e[l]!==void 0&&(a[l]=e[l]);return m(e.model)&&(a.model=m(e.model)),{form:h,extras:a,warnings:i}},render(t){const o=t||{},e=o.dialectExtras?.claude||{},n={name:o.id||o.name||"agent",description:o.purpose||o.name||""},i=o.grants?.length?b(o.grants,{dialect:"claude"}):d(e.tools);i.length&&(n.tools=i),e.disallowedTools&&(n.disallowedTools=e.disallowedTools);const r=v(o,e);r&&(n.model=r),o.skills?.length&&(n.skills=[...o.skills]),e.mcpServers&&(n.mcpServers=e.mcpServers);for(const s of["permissionMode","maxTurns","memory","background","omitClaudeMd","effort","isolation","color","initialPrompt","experimental","hooks"])e[s]!==void 0&&(n[s]=e[s]);for(const[s,c]of Object.entries(e.raw||{}))n[s]===void 0&&(n[s]=c);return k(n,`
2
2
  ${String(o.prompt||"").trim()}
3
3
  `)},carries:["id","name","purpose","prompt","engine","grants","skills","mcpServers","tools","denyTools","permissionMode","maxTurns","effort","isolation","color","background","hooks"],notes:{sandboxMode:"Claude Code has no sandbox_mode; its equivalent is permissionMode plus the tools allowed",memoryScope:"Claude Code scopes memory to user, project or local — not to a named namespace",workdir:"a Claude Code agent runs wherever the session runs; a working directory is not part of its definition",provider:"a definition file describes an agent, not who publishes it — that is A2A card territory",version:"a definition file carries no version of its own",iconUrl:"no icon in the format",documentationUrl:"no documentation link in the format",tags:"no tags in the format",examples:'no examples in the format — the description is where the "use this when" goes',inputModes:"media types are an A2A idea",outputModes:"media types are an A2A idea"}});function y(t){const o=m(t);return!o||o==="inherit"?o==="inherit"?{kind:"assistant"}:{kind:"harness",harnessId:"claude"}:{kind:"harness",harnessId:"claude",model:o}}function v(t,o){const e=t?.engine;return e?.kind==="assistant"?"inherit":e?.kind==="harness"&&e.harnessId==="claude"&&e.model||e?.kind==="model"&&e.model&&/claude|sonnet|opus|haiku/i.test(String(e.model))?String(e.model):o.model?String(o.model):""}export{A as claudeDialect};
package/digest.js ADDED
@@ -0,0 +1,7 @@
1
+ import{splitForWindow as I,partChars as E,partPrompt as L,mapParts as C,reduceNotes as D,STITCH_LIMITS as F}from"./stitch.js";const N=/\b(?:summari[sz]e|summary|sum (?:it |this )?up|tl;?\s?dr|recap|overview|the gist|key (?:points|takeaways|ideas)|main (?:points|ideas|themes|arguments)|highlights|outline|what(?:'s| is| are)? (?:it|(?:this|that|the)(?: (?:page|article|post|thread|discussion|doc|document|paper|video|meeting|transcript|story|site))?) (?:about|saying)|what (?:are )?(?:people|they|folks|commenters) (?:saying|think(?:ing)?))\b/i,P=/\b(?:about|regarding|on the (?:topic|subject) of|concerning|re:)\s+(?!it\b|this\b|that\b|the (?:page|article|post|thread|discussion|doc|document|content|paper|video)\b)\S/i;function j(c){const n=String(c||"").trim();if(!n||!N.test(n))return!1;const s=n.replace(/\bwhat(?:'s| is| are)? (?:it|(?:this|that|the)(?: \w+)?) about\b/i,"");return!P.test(s)}async function B({text:c="",title:n="",question:s="",kind:x="page",windowTokens:S=0,budgetChars:o=0,complete:d=null,concurrency:f=1,onProgress:k=null,late:u=()=>!1}={}){const g=String(c||"");if(!g.trim()||typeof d!="function"||!(o>200))return null;const a=E({windowTokens:S,reserveTokens:450}),e=I(g,{maxChars:a>0?a:Math.max(1200,o)}),l=e.slice(0,F.parts),r=t=>{try{k?.(t)}catch{}};let p=0;r({phase:"read",done:0,of:l.length});const w=await C(l,async t=>{const i=await d(L({question:s,title:n,part:t,kind:x,words:"3-8 short bullet points"}),{maxTokens:320}),A=String(i||"").split(`
2
+ `).map(h=>h.replace(/^[\s*•-]+/,"").trim()).find(h=>h&&!/^none\.?$/i.test(h))||"";return r({phase:"read",done:++p,of:l.length,note:A.slice(0,140)}),i},{concurrency:f,late:u}),b=w.filter(Boolean).length;if(!b)return null;const v=w.map((t,i)=>t?`(part ${i+1} of ${e.length})
3
+ ${t}`:"").filter(Boolean);r({phase:"merge",done:0,of:1});const $=await D(v,{question:s,budgetChars:o-200,batchChars:a>0?a:o,complete:d,concurrency:f,late:u});r({phase:"merge",done:1,of:1});const T=$.some(t=>/\(cut: the rest did not fit the model\)/.test(t)),m=p===e.length,y=`"${n||"the text"}"`;return{text:`${m?`(READ IN FULL: all ${e.length} part${e.length===1?"":"s"} of ${y} were read and noted in order, and the notes combined — they cover the whole of it. Answer from them.)`:`(READ IN PART: the first ${p} of ${e.length} parts of ${y} were read and noted in order; the rest were not read. Answer from these notes, and say that the end was not read.)`}
4
+
5
+ ${$.join(`
6
+
7
+ `)}`,parts:e.length,read:b,whole:m,cut:T||!m}}export{B as digest,j as needsWhole};
package/fetched.js CHANGED
@@ -1,3 +1,3 @@
1
- import{approxTokens as T,queryTerms as A}from"./sources-retrieval.js";import{effectiveToolName as N}from"./tool-traits.js";const b=Object.freeze({weather:10*6e4,web_search:30*6e4,history_search:10*6e4,history_get_source:30*6e4,history_related:10*6e4,history_list_meetings:10*6e4,history_get_meeting:30*6e4,meeting_live_transcript:6e4,read_page:5*6e4,read_transcript:30*6e4,mcp:10*6e4,default:5*6e4}),j=new Set(["source","get_result","describe","find_tool","team","sideline","thread","memory","note","skill_open","skill_file","screenshot","marked_screenshot","inspect_page","sense_canvas","probe_app_state","read_app_state","read_canvas"]);function q(t,r){return b[t]?b[t]:r==="mcp"||/^mcp[_:]/.test(String(r||""))?b.mcp:b.default}function $(t){if(t!=null){if(typeof t=="string")return t.trim().toLowerCase().replace(/\s+/g," ");if(Array.isArray(t))return t.map($);if(typeof t=="object"){const r={};for(const c of Object.keys(t).sort()){const a=$(t[c]);a!==void 0&&a!==""&&(r[c]=a)}return r}return t}}function O(t,r,{hiddenVia:c=null}={}){const a=typeof r=="string"?(()=>{try{return JSON.parse(r)}catch{return{text:r}}})():r||{},h=N(t,a);let y=a;if(a&&typeof a=="object"&&("args"in a||"action"in a)){const{action:k,args:d,...e}=a;y={...e,...d&&typeof d=="object"?d:{}}}const s=$(y)||{},m=h!==t&&c instanceof Map&&c.get(h)!==t?`${t}.${h}`:h;return{tool:String(t||""),action:h,args:s,key:`${m}|${JSON.stringify(s)}`}}function J(t){if(!t||typeof t!="object")return"";for(const r of["location","query","q","url","id","sourceId","name","text","path"])if(typeof t[r]=="string"&&t[r])return t[r];for(const r of Object.values(t))if(typeof r=="string"&&r)return r;return""}function D(t,r){const c=J(r);return c?`${t} — ${c.slice(0,60)}`:t}const E=t=>!t||/^(error\b|\w+ failed\b|\{"error"|could not answer)/i.test(String(t))||/now call web_search/i.test(String(t));function C({entries:t=[],now:r=()=>Date.now(),ttlFor:c=q,maxEntries:a=40,maxTokens:h=24e3,newId:y=null}={}){let s=(Array.isArray(t)?t:[]).filter(e=>e&&e.id&&e.key&&typeof e.text=="string").map(e=>({...e})),x=s.reduce((e,n)=>Math.max(e,Number(String(n.id).replace(/^f/,""))||0),0);const m=()=>y?y():`f${++x}`,k=(e,n=r())=>n-(e.at||0)<(e.ttl||c(e.action,e.tool)),d=()=>{const e=r();for(s=s.filter(i=>k(i,e));s.length>a;)s.shift();let n=s.reduce((i,f)=>i+f.tokens,0);for(;n>h&&s.length>1;)n-=s.shift().tokens};return{get entries(){return d(),[...s]},get tokens(){return d(),s.reduce((e,n)=>e+n.tokens,0)},remember({tool:e,input:n,text:i,title:f="",turn:_=null,exchange:l=null,hiddenVia:p=null}={}){const o=typeof i=="string"?i:i&&typeof i=="object"&&typeof i.text=="string"?i.text:"";if(E(o))return null;const u=O(e,n,{hiddenVia:p});s=s.filter(S=>S.key!==u.key);const g={id:m(),tool:u.tool,action:u.action,key:u.key,args:u.args,title:f||D(u.action,u.args),text:o,tokens:T(o),at:r(),ttl:c(u.action,u.tool),uses:0,turn:_,...Number.isInteger(l)?{exchange:l}:{}};return s.push(g),d(),g},lookup(e,n,{hiddenVia:i=null}={}){const f=O(e,n,{hiddenVia:i}),_=s.find(l=>l.key===f.key);return _&&k(_)?_:null},byId(e){const n=s.find(i=>i.id===String(e||"").trim());return n&&k(n)?n:null},relevant(e,{limit:n=4,previousTurn:i=null,exchange:f=null}={}){d();const _=A(String(e||"")),l=r();return s.map(o=>{const u=`${o.title} ${JSON.stringify(o.args)} ${o.text.slice(0,400)}`.toLowerCase();let g=0;for(const w of _)u.includes(w)&&(g+=Math.min(3,w.length/4));const S=(l-o.at)/6e4;return(Number.isInteger(f)?o.exchange===f-1:i!=null&&o.turn===i)&&(g+=2),{e:o,s:g>0?g+Math.max(0,1-S/30):0}}).filter(o=>o.s>0).sort((o,u)=>u.s-o.s).slice(0,n).map(o=>o.e)},use(e){const n=s.find(i=>i.id===e);n&&(n.uses+=1)},toJSON(){return d(),s.map(e=>({...e}))},now:r}}function F(t=[]){return(Array.isArray(t)?t:[]).filter(r=>r?.role==="user").length}function L(t=[]){return t.map(r=>({id:r.id,kind:"fetched",title:r.title,url:"",text:r.text}))}const M=t=>{const r=Math.floor(t/6e4);return r<1?"just now":`${r} min ago`};function z(t=[],{now:r=Date.now()}={}){return t.map(c=>({id:c.id,title:c.title,agoText:M(r-(c.at||r)),tokens:c.tokens}))}function B(t,r,{traitsOf:c=null,cacheable:a=null,now:h=null,turn:y=null,exchange:s=null}={}){if(!t||typeof t.execute!="function"||!r)return t;const x=h||r.now||(()=>Date.now()),m=c||(e=>t.traits?.get?.(e)||null),k=a||(e=>/^(history_|web_search$|weather$|read_page$|read_transcript$|list_|get_|search|fetch|read_|find_)/.test(e)),d=(e,n)=>{if(j.has(e)||j.has(n))return!1;const i=m(e)||m(n);return i?!!i.readOnly&&!i.destructive:k(e,n)};return{...t,async execute(e,n,i){const f=typeof n=="string"?(()=>{try{return JSON.parse(n)}catch{return n}})():n,_=N(e,f);if(!d(_,e))return t.execute(e,n,i);const l=r.lookup(e,f,{hiddenVia:t.hiddenVia});if(l)return r.use(l.id),{text:`${l.text}
1
+ import{approxTokens as T,queryTerms as A}from"./sources-retrieval.js";import{effectiveToolName as j}from"./tool-traits.js";const S=Object.freeze({weather:10*6e4,web_search:30*6e4,history_search:10*6e4,history_get_source:30*6e4,history_related:10*6e4,history_list_meetings:10*6e4,history_get_meeting:30*6e4,meeting_live_transcript:6e4,read_transcript:30*6e4,mcp:10*6e4,default:5*6e4}),x=new Set(["source","get_result","describe","find_tool","team","sideline","thread","memory","note","skill_open","skill_file","screenshot","marked_screenshot","inspect_page","read_page","sense_canvas","probe_app_state","read_app_state","read_canvas"]);function q(t,r){return S[t]?S[t]:r==="mcp"||/^mcp[_:]/.test(String(r||""))?S.mcp:S.default}function w(t){if(t!=null){if(typeof t=="string")return t.trim().toLowerCase().replace(/\s+/g," ");if(Array.isArray(t))return t.map(w);if(typeof t=="object"){const r={};for(const c of Object.keys(t).sort()){const a=w(t[c]);a!==void 0&&a!==""&&(r[c]=a)}return r}return t}}function O(t,r,{hiddenVia:c=null}={}){const a=typeof r=="string"?(()=>{try{return JSON.parse(r)}catch{return{text:r}}})():r||{},h=j(t,a);let _=a;if(a&&typeof a=="object"&&("args"in a||"action"in a)){const{action:k,args:d,...e}=a;_={...e,...d&&typeof d=="object"?d:{}}}const s=w(_)||{},m=h!==t&&c instanceof Map&&c.get(h)!==t?`${t}.${h}`:h;return{tool:String(t||""),action:h,args:s,key:`${m}|${JSON.stringify(s)}`}}function J(t){if(!t||typeof t!="object")return"";for(const r of["location","query","q","url","id","sourceId","name","text","path"])if(typeof t[r]=="string"&&t[r])return t[r];for(const r of Object.values(t))if(typeof r=="string"&&r)return r;return""}function D(t,r){const c=J(r);return c?`${t} — ${c.slice(0,60)}`:t}const E=t=>!t||/^(error\b|\w+ failed\b|\{"error"|could not answer)/i.test(String(t))||/now call web_search/i.test(String(t));function C({entries:t=[],now:r=()=>Date.now(),ttlFor:c=q,maxEntries:a=40,maxTokens:h=24e3,newId:_=null}={}){let s=(Array.isArray(t)?t:[]).filter(e=>e&&e.id&&e.key&&typeof e.text=="string").map(e=>({...e})),b=s.reduce((e,n)=>Math.max(e,Number(String(n.id).replace(/^f/,""))||0),0);const m=()=>_?_():`f${++b}`,k=(e,n=r())=>n-(e.at||0)<(e.ttl||c(e.action,e.tool)),d=()=>{const e=r();for(s=s.filter(i=>k(i,e));s.length>a;)s.shift();let n=s.reduce((i,l)=>i+l.tokens,0);for(;n>h&&s.length>1;)n-=s.shift().tokens};return{get entries(){return d(),[...s]},get tokens(){return d(),s.reduce((e,n)=>e+n.tokens,0)},remember({tool:e,input:n,text:i,title:l="",turn:y=null,exchange:f=null,hiddenVia:p=null}={}){const o=typeof i=="string"?i:i&&typeof i=="object"&&typeof i.text=="string"?i.text:"";if(E(o))return null;const u=O(e,n,{hiddenVia:p});if(x.has(u.action)||x.has(u.tool))return null;s=s.filter($=>$.key!==u.key);const g={id:m(),tool:u.tool,action:u.action,key:u.key,args:u.args,title:l||D(u.action,u.args),text:o,tokens:T(o),at:r(),ttl:c(u.action,u.tool),uses:0,turn:y,...Number.isInteger(f)?{exchange:f}:{}};return s.push(g),d(),g},lookup(e,n,{hiddenVia:i=null}={}){const l=O(e,n,{hiddenVia:i});if(x.has(l.action)||x.has(l.tool))return null;const y=s.find(f=>f.key===l.key);return y&&k(y)?y:null},byId(e){const n=s.find(i=>i.id===String(e||"").trim());return n&&k(n)?n:null},relevant(e,{limit:n=4,previousTurn:i=null,exchange:l=null}={}){d();const y=A(String(e||"")),f=r();return s.map(o=>{const u=`${o.title} ${JSON.stringify(o.args)} ${o.text.slice(0,400)}`.toLowerCase();let g=0;for(const N of y)u.includes(N)&&(g+=Math.min(3,N.length/4));const $=(f-o.at)/6e4;return(Number.isInteger(l)?o.exchange===l-1:i!=null&&o.turn===i)&&(g+=2),{e:o,s:g>0?g+Math.max(0,1-$/30):0}}).filter(o=>o.s>0).sort((o,u)=>u.s-o.s).slice(0,n).map(o=>o.e)},use(e){const n=s.find(i=>i.id===e);n&&(n.uses+=1)},toJSON(){return d(),s.map(e=>({...e}))},now:r}}function F(t=[]){return(Array.isArray(t)?t:[]).filter(r=>r?.role==="user").length}function L(t=[]){return t.map(r=>({id:r.id,kind:"fetched",title:r.title,url:"",text:r.text}))}const M=t=>{const r=Math.floor(t/6e4);return r<1?"just now":`${r} min ago`};function z(t=[],{now:r=Date.now()}={}){return t.map(c=>({id:c.id,title:c.title,agoText:M(r-(c.at||r)),tokens:c.tokens}))}function B(t,r,{traitsOf:c=null,cacheable:a=null,now:h=null,turn:_=null,exchange:s=null}={}){if(!t||typeof t.execute!="function"||!r)return t;const b=h||r.now||(()=>Date.now()),m=c||(e=>t.traits?.get?.(e)||null),k=a||(e=>/^(history_|web_search$|weather$|read_page$|read_transcript$|list_|get_|search|fetch|read_|find_)/.test(e)),d=(e,n)=>{if(x.has(e)||x.has(n))return!1;const i=m(e)||m(n);return i?!!i.readOnly&&!i.destructive:k(e,n)};return{...t,async execute(e,n,i){const l=typeof n=="string"?(()=>{try{return JSON.parse(n)}catch{return n}})():n,y=j(e,l);if(!d(y,e))return t.execute(e,n,i);const f=r.lookup(e,l,{hiddenVia:t.hiddenVia});if(f)return r.use(f.id),{text:`${f.text}
2
2
 
3
- (cached: the same request was answered ${M(x()-l.at)}; not fetched again)`,note:"cached",cached:!0,fetchedId:l.id};const p=await t.execute(e,n,i),o=typeof p=="string"?p:p&&typeof p=="object"&&typeof p.text=="string"?p.text:"";return o&&r.remember({tool:e,input:f,text:o,turn:y,exchange:s,hiddenVia:t.hiddenVia}),p}}}export{b as FETCHED_TTL_MS,C as createFetchedStore,q as defaultTtl,F as exchangeOf,O as fetchKey,D as fetchTitle,L as fetchedAsSources,z as fetchedFacts,B as withFetchedMemo};
3
+ (cached: the same request was answered ${M(b()-f.at)}; not fetched again)`,note:"cached",cached:!0,fetchedId:f.id};const p=await t.execute(e,n,i),o=typeof p=="string"?p:p&&typeof p=="object"&&typeof p.text=="string"?p.text:"";return o&&r.remember({tool:e,input:l,text:o,turn:_,exchange:s,hiddenVia:t.hiddenVia}),p}}}export{S as FETCHED_TTL_MS,C as createFetchedStore,q as defaultTtl,F as exchangeOf,O as fetchKey,D as fetchTitle,L as fetchedAsSources,z as fetchedFacts,B as withFetchedMemo};
package/find-tool.js CHANGED
@@ -1 +1 @@
1
- import{makeDispatchProvider as a}from"./tool-dispatch.js";const n="find",r='Search and read the user\'s own saved data (past chats, notes, meetings) and the web. Pass an `action` and put that action\'s own arguments inside `args`, e.g. {"action":"history_search","args":{"query":"pricing"}}. Unsure of an action\'s arguments? {"action":"describe","args":{"tool":"<action>"}} returns its full schema. Use this when the answer plausibly depends on something the user already has; do not call it for greetings or general knowledge.',o="You HAVE access to the user's own ChatPanel data — past chats, notes, meeting transcripts and summaries — through `find`, plus the web. For anything they discussed or wrote, call `find` FIRST and answer from it; never say you cannot access their meetings, notes or history. For anything current — weather, prices, news — use `find` (actions `weather`, `web_search`), not a search tool of your own; the user sees `find` calls as steps. A [prefetch] block in the message IS that call, already made: answer from it, no call. A search returns excerpts, not the record: before reporting details (action items, decisions, who said what) read the full record by its id — each result names the action.";function c(e,{all:t=null,rank:s=void 0}={}){return a({name:n,description:r,resident:o,inner:e,remote:!1,all:t,rank:s})}export{r as FIND_DESCRIPTION,o as FIND_RESIDENT,n as FIND_TOOL_NAME,c as findDispatchProvider};
1
+ import{makeDispatchProvider as a}from"./tool-dispatch.js";const n="find",r='Search and read the user\'s own saved data (past chats, notes, meetings) and the web. Pass an `action` and put that action\'s own arguments inside `args`, e.g. {"action":"history_search","args":{"query":"pricing"}}. Unsure of an action\'s arguments? {"action":"describe","args":{"tool":"<action>"}} returns its full schema. Use this when the answer plausibly depends on something the user already has; do not call it for greetings or general knowledge.',o="You HAVE access to the user's own Chap data — past chats, notes, meeting transcripts and summaries — through `find`, plus the web. For anything they discussed or wrote, call `find` FIRST and answer from it; never say you cannot access their meetings, notes or history. For anything current — weather, prices, news — use `find` (actions `weather`, `web_search`), not a search tool of your own; the user sees `find` calls as steps. A [prefetch] block in the message IS that call, already made: answer from it, no call. A search returns excerpts, not the record: before reporting details (action items, decisions, who said what) read the full record by its id — each result names the action.";function c(e,{all:t=null,rank:s=void 0}={}){return a({name:n,description:r,resident:o,inner:e,remote:!1,all:t,rank:s})}export{r as FIND_DESCRIPTION,o as FIND_RESIDENT,n as FIND_TOOL_NAME,c as findDispatchProvider};
package/harness-cards.js CHANGED
@@ -1 +1 @@
1
- import{EventError as l}from"./event.js";const i=Object.freeze({claude:{label:"Claude Code",vendor:"Anthropic",hosts:["api.anthropic.com"],repoint:"limited",how:"ANTHROPIC_BASE_URL (+ ANTHROPIC_AUTH_TOKEN) to an Anthropic-compatible endpoint — this gateway’s /v1/messages qualifies",dirs:{flag:"--add-dir",repeat:!0},defaultModel:"cloud"},codex:{label:"Codex",vendor:"OpenAI",hosts:["api.openai.com","chatgpt.com"],repoint:"limited",how:"OPENAI_BASE_URL, or a model_provider in ~/.codex/config.toml pointing at an OpenAI-compatible endpoint",dirs:{flag:"--add-dir",repeat:!0},defaultModel:"cloud",ownSandbox:"computer use (controlling the browser and other apps)"},antigravity:{label:"Antigravity",vendor:"Google",hosts:["*.googleapis.com"],repoint:"no",how:"",dirs:null,defaultModel:"cloud"},kiro:{label:"Kiro",vendor:"AWS",hosts:["*.amazonaws.com"],repoint:"no",how:"",dirs:null,defaultModel:"cloud"},copilot:{label:"GitHub Copilot",vendor:"GitHub",hosts:["api.githubcopilot.com","*.github.com"],repoint:"no",how:"",dirs:{flag:"--add-dir",repeat:!0},defaultModel:"cloud"},deepseek:{label:"DeepSeek Harness",vendor:"DeepSeek",hosts:["api.deepseek.com"],repoint:"limited",how:"its base URL setting, to an OpenAI-compatible endpoint",dirs:null,defaultModel:"cloud"},opencode:{label:"OpenCode",vendor:null,hosts:[],repoint:"yes",how:"a provider in its config — any OpenAI-compatible endpoint, Ollama, LM Studio, or this gateway",dirs:null,defaultModel:"configurable"},pi:{label:"Pi",vendor:null,hosts:[],repoint:"yes",how:"a provider in its config — any OpenAI-compatible endpoint, or this gateway",dirs:null,defaultModel:"configurable"},hermes:{label:"Hermes",vendor:null,hosts:[],repoint:"yes",how:"a provider in its config — a local model is a first-class choice",dirs:null,defaultModel:"configurable"}}),c=t=>String(t||"").toLowerCase().replace(/[^a-z]/g,""),s={claudecode:"claude",githubcopilot:"copilot",copilotcli:"copilot",deepseekharness:"deepseek",gemini:"antigravity",geminicli:"antigravity"};function d(t){const o=c(t);if(i[o])return{id:o,...i[o]};if(s[o])return{id:s[o],...i[s[o]]};const e=Object.entries(i).find(([r,n])=>o.includes(r)||o.includes(c(n.label)));return e?{id:e[0],...e[1]}:null}function g(t,{repointed:o=null}={}){const e=d(t);return e?o?{egress:"configurable",where:`a coding agent · model at ${o}`,note:`Re-pointed by you; ${e.how||"its own setting"}.`}:e.repoint==="yes"?{egress:"configurable",where:"a coding agent · model of your choosing",note:`Its model is a setting of its own — ${e.how}. Until you set one, whatever it defaults to.`}:e.repoint==="limited"?{egress:"internet",where:`a coding agent · model at ${e.vendor}`,note:`The conversation goes to ${e.vendor} with your own login. It can be re-pointed: ${e.how}.`}:{egress:"internet",where:`a coding agent · model at ${e.vendor}`,note:`The conversation goes to ${e.vendor} with your own login; this agent cannot be pointed elsewhere.`}:{egress:"internet",where:"a coding agent · its own model, elsewhere",note:"No card for this agent — assume its model is a vendor’s until you know otherwise."}}function u(t){if(t==null)return null;if(typeof t=="string")return u({flag:t,repeat:!0});if(typeof t!="object"||Array.isArray(t))throw new l("SHAPE","dirs: must be { flag, repeat } or { flag, separator }");const o=String(t.flag||"").trim();if(!/^--?[A-Za-z][\w-]*$/.test(o))throw new l("SHAPE",`dirs: not a flag: ${JSON.stringify(t.flag)}`);const e=t.separator==null?null:String(t.separator);if(e!=null&&(e.length===0||/\s/.test(e)))throw new l("SHAPE","dirs: separator must be a non-empty run of non-space characters");return e!=null?{flag:o,separator:e}:{flag:o,repeat:!0}}function f({harness:t,roots:o=[],dirs:e}={}){const r=(Array.isArray(o)?o:[]).map(a=>String(a||"").trim()).filter(Boolean);if(!r.length)return[];const n=u(e!==void 0?e:d(t)?.dirs??null);return n?n.separator?[n.flag,r.join(n.separator)]:r.flatMap(a=>[n.flag,a]):[]}function h(t,o){try{return!!u(o!==void 0?o:d(t)?.dirs??null)}catch{return!1}}export{i as HARNESS_CARDS,d as harnessCard,f as harnessDirArgs,g as harnessEgress,h as harnessTakesDirs,u as normalizeDirsSpec};
1
+ import{EventError as a}from"./event.js";const l=Object.freeze({claude:{label:"Claude Code",vendor:"Anthropic",hosts:["api.anthropic.com"],repoint:"limited",how:"ANTHROPIC_BASE_URL (+ ANTHROPIC_AUTH_TOKEN) to an Anthropic-compatible endpoint — this gateway’s /v1/messages qualifies",dirs:{flag:"--add-dir",repeat:!0},defaultModel:"cloud",session:{resume:["--resume","{id}"],off:["--no-session-persistence"],name:["--name","{name}"]}},codex:{label:"Codex",vendor:"OpenAI",hosts:["api.openai.com","chatgpt.com"],repoint:"limited",how:"OPENAI_BASE_URL, or a model_provider in ~/.codex/config.toml pointing at an OpenAI-compatible endpoint",dirs:{flag:"--add-dir",repeat:!0},defaultModel:"cloud",ownSandbox:"computer use (controlling the browser and other apps)",session:{resume:["resume","{id}"],off:["--ephemeral"]}},antigravity:{label:"Antigravity",vendor:"Google",hosts:["*.googleapis.com"],repoint:"no",how:"",dirs:null,defaultModel:"cloud"},kiro:{label:"Kiro",vendor:"AWS",hosts:["*.amazonaws.com"],repoint:"no",how:"",dirs:null,defaultModel:"cloud"},copilot:{label:"GitHub Copilot",vendor:"GitHub",hosts:["api.githubcopilot.com","*.github.com"],repoint:"no",how:"",dirs:{flag:"--add-dir",repeat:!0},defaultModel:"cloud",session:{resume:["--session-id","{id}"],off:null,name:["--name","{name}"]}},deepseek:{label:"DeepSeek Harness",vendor:"DeepSeek",hosts:["api.deepseek.com"],repoint:"limited",how:"its base URL setting, to an OpenAI-compatible endpoint",dirs:null,defaultModel:"cloud"},opencode:{label:"OpenCode",vendor:null,hosts:[],repoint:"yes",how:"a provider in its config — any OpenAI-compatible endpoint, Ollama, LM Studio, or this gateway",dirs:null,defaultModel:"configurable",session:{resume:["--session","{id}"],off:null,name:["--title","{name}"]}},pi:{label:"Pi",vendor:null,hosts:[],repoint:"yes",how:"a provider in its config — any OpenAI-compatible endpoint, or this gateway",dirs:null,defaultModel:"configurable"},hermes:{label:"Hermes",vendor:null,hosts:[],repoint:"yes",how:"a provider in its config — a local model is a first-class choice",dirs:null,defaultModel:"configurable"}}),p=n=>String(n||"").toLowerCase().replace(/[^a-z]/g,""),d={claudecode:"claude",githubcopilot:"copilot",copilotcli:"copilot",deepseekharness:"deepseek",gemini:"antigravity",geminicli:"antigravity"};function s(n){const o=p(n);if(l[o])return{id:o,...l[o]};if(d[o])return{id:d[o],...l[d[o]]};const e=Object.entries(l).find(([i,t])=>o.includes(i)||o.includes(p(t.label)));return e?{id:e[0],...e[1]}:null}function m(n,{repointed:o=null}={}){const e=s(n);return e?o?{egress:"configurable",where:`a coding agent · model at ${o}`,note:`Re-pointed by you; ${e.how||"its own setting"}.`}:e.repoint==="yes"?{egress:"configurable",where:"a coding agent · model of your choosing",note:`Its model is a setting of its own — ${e.how}. Until you set one, whatever it defaults to.`}:e.repoint==="limited"?{egress:"internet",where:`a coding agent · model at ${e.vendor}`,note:`The conversation goes to ${e.vendor} with your own login. It can be re-pointed: ${e.how}.`}:{egress:"internet",where:`a coding agent · model at ${e.vendor}`,note:`The conversation goes to ${e.vendor} with your own login; this agent cannot be pointed elsewhere.`}:{egress:"internet",where:"a coding agent · its own model, elsewhere",note:"No card for this agent — assume its model is a vendor’s until you know otherwise."}}function u(n){if(n==null)return null;if(typeof n=="string")return u({flag:n,repeat:!0});if(typeof n!="object"||Array.isArray(n))throw new a("SHAPE","dirs: must be { flag, repeat } or { flag, separator }");const o=String(n.flag||"").trim();if(!/^--?[A-Za-z][\w-]*$/.test(o))throw new a("SHAPE",`dirs: not a flag: ${JSON.stringify(n.flag)}`);const e=n.separator==null?null:String(n.separator);if(e!=null&&(e.length===0||/\s/.test(e)))throw new a("SHAPE","dirs: separator must be a non-empty run of non-space characters");return e!=null?{flag:o,separator:e}:{flag:o,repeat:!0}}function h({harness:n,roots:o=[],dirs:e}={}){const i=(Array.isArray(o)?o:[]).map(r=>String(r||"").trim()).filter(Boolean);if(!i.length)return[];const t=u(e!==void 0?e:s(n)?.dirs??null);return t?t.separator?[t.flag,i.join(t.separator)]:i.flatMap(r=>[t.flag,r]):[]}function w(n,o){try{return!!u(o!==void 0?o:s(n)?.dirs??null)}catch{return!1}}const f=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;function A({harness:n,mode:o,id:e="",name:i=""}={}){const t=s(n)?.session;if(!t)return[];if(o==="off")return Array.isArray(t.off)?[...t.off]:[];if(o==="name"){const r=String(i??"").replace(/\s+/g," ").trim().slice(0,120);return!r||r.startsWith("-")||!Array.isArray(t.name)?[]:t.name.map(c=>c==="{name}"?r:c)}if(o!=="resume"||!Array.isArray(t.resume))return[];if(!f.test(String(e)))throw new a("SHAPE",`harness session: ${JSON.stringify(String(e).slice(0,40))} is not a session id`);return t.resume.map(r=>r==="{id}"?String(e):r)}const y=n=>Array.isArray(s(n)?.session?.resume);export{l as HARNESS_CARDS,s as harnessCard,h as harnessDirArgs,m as harnessEgress,y as harnessResumes,A as harnessSessionArgs,w as harnessTakesDirs,u as normalizeDirsSpec};
package/history-search.js CHANGED
@@ -1,8 +1,8 @@
1
- import{bm25Search as I,buildGraph as A,buildIndex as E,tokenize as M,topTerms as H}from"./text-index.js";const $=1800,C=220,F=new Set("chat chats history source sources search result results local previous prior past meeting meetings meet meets call calls transcript transcripts recording recordings conversation conversations discuss discussed discussing find show list had have".split(/\s+/));function h(t){return String(t||"").replace(/\s+/g," ").trim()}function m(t,n,e,s){const i=Number(t);return Number.isFinite(i)?Math.max(e,Math.min(s,Math.floor(i))):n}function R(t){return String(t||"").toLowerCase()==="exact"?"exact":"best"}function y(t){const n=String(t||"").toLowerCase();return n==="title"||n==="name"?"title":n==="content"||n==="body"||n==="text"||n==="transcript"?"content":"all"}function w(t,n,e){const s=n==="meetings"||n==="chats"||n==="notes"?n:"all";return(t||[]).filter(i=>!e&&i.type==="meeting"?!1:s==="meetings"?i.type==="meeting":s==="chats"?i.type==="chat":s==="notes"?i.type==="note":i.type==="chat"||i.type==="meeting"||i.type==="note")}function g(t,{maxChunkChars:n=$,overlapChars:e=C}={}){const s=h(t?.text);if(!t?.id||!t?.type||!s)return[];const i=m(n,$,400,8e3),c=m(e,C,0,Math.floor(i/2)),o=[];let r=0,a=0;for(;r<s.length;){let u=Math.min(s.length,r+i);if(u<s.length){const f=s.lastIndexOf(" ",u);f>r+Math.floor(i*.6)&&(u=f)}const l=s.slice(r,u).trim();if(l&&(o.push({id:`${t.id}#${a}`,sourceId:t.id,chunk:a,type:t.type,title:t.title||(t.type==="meeting"?"Meeting":t.type==="note"?"Note":"Chat"),date:t.date||0,text:l,url:t.url||"",meta:t.meta||{}}),a+=1),u>=s.length)break;r=Math.max(0,u-c)}return o}function J(t,n={}){return(t||[]).flatMap(e=>g(e,n))}function j(t,n){return y(n)==="content"&&t&&t.contentText!=null?{...t,text:t.contentText}:t}function b(t,n={},e="all"){return(t||[]).flatMap(s=>g(j(s,e),n))}function T(t){return/\b(?:1\s*[:x]\s*1|1\s*[-\s]*(?:on|to)\s*[-\s]*1|one\s*[-\s]*on\s*[-\s]*one|one\s*[-\s]*to\s*[-\s]*one)\b/i.test(String(t||""))}function N(t){return{terms:[...new Set(M(t).filter(e=>!F.has(e)))],directMeeting:T(t)}}function L(t,n){const e=String(n||"").toLowerCase();let s=0;for(const i of t||[])e.includes(i)&&(s+=1);return s}const D=16,v=12;function B(t,n){const e=n?.get(t);return e==null?1.5:e<=.15?.15:Math.min(e,3)}function O(t,n,e,s){if(!t||s==="content"||!n?.length)return 0;const i=String(t.title||"").toLowerCase(),c=Array.isArray(t.meta?.people)?t.meta.people.join(" ").toLowerCase():"";let o=0;for(const r of n){const a=B(r,e);i.includes(r)&&(o+=a*D),c&&c.includes(r)&&(o+=a*v)}return o}function P(t,n,e){if(!t||t.type!=="meeting"||e==="content")return 0;const s=n?.terms||[];if(!s.length&&!n?.directMeeting)return 0;const i=String(t.title||""),c=Array.isArray(t.meta?.people)?t.meta.people:[],o=c.join(" "),r=L(s,i),a=L(s,o);let u=r*45+a*28;return n?.directMeeting&&(T(i)&&(u+=80),r&&(u+=35),a&&(u+=25),a&&c.length>0&&c.length<=2&&(u+=70)),u}function k(t,n){const e=(t||[]).filter(l=>l?.sourceId).sort((l,f)=>f.score-l.score||(f.date||0)-(l.date||0)),s=e[0]?.score||0,i=s>0?s*.5:0,c=[],o=[],r=[],a=new Set,u=new Set;for(const l of e)a.has(l.sourceId)?u.has(l.sourceId)?r.push(l):o.push(l):(a.add(l.sourceId),l.score>=i?c.push(l):(u.add(l.sourceId),r.push(l)));return[...c,...o,...r].slice(0,n).map((l,f)=>({...l,rank:f+1}))}const z=45,q=.3;function U(t,n=Date.now()){if(!t)return 1;const e=Math.max(0,(n-t)/864e5);return 1+q*Math.exp(-e/z)}function Y(t,n={}){const e=w(t,n.scope||"all",n.includeMeetings!==!1),s=y(n.field),i=b(e,n,s),c=s==="title"?_(e,n).map(r=>({id:r.id,text:r.title})):i.map(r=>({id:r.id,text:s==="content"?r.text:`${r.title}
2
- ${r.text}`})),o=new Map(i.map(r=>[r.id,r]));for(const r of _(e,n))o.set(r.id,r);return{idx:E(c),byId:o,field:s}}function W(t,n,e={}){const s=m(e.limit,8,1,30),i=h(n);if(!i||!t?.idx)return[];const{idx:c,byId:o,field:r}=t,a=i.toLowerCase(),u=M(a),l=N(i),f=I(c,i).map(x=>{const p=o.get(x.id);let d=x.score;const S=String(p?.title||"").toLowerCase();return r!=="content"&&(S===a?d+=80:S.includes(a)&&(d+=50)),d+=O(p,u,c.idf,r),d+=P(p,l,r),e.recency&&(d*=U(p?.date,e.now)),{...p,score:d}});return k(f,s)}function tt(t,n,e={}){const s=R(e.mode),i=h(n);if(!i)return[];if(s==="exact"){const c=w(t,e.scope||"all",e.includeMeetings!==!1);return G(c,i,{...e,field:y(e.field),limit:m(e.limit,8,1,30)})}return W(Y(t,e),n,e)}function _(t,n={}){return(t||[]).map(e=>g(e,n)[0]).filter(Boolean)}function G(t,n,e={}){const s=y(e.field),i=n.toLowerCase(),c=[];if(s==="title")for(const o of t||[]){const r=h(o?.title).toLowerCase();if(!r.includes(i))continue;const a=g(o,e)[0];a&&c.push({...a,score:r===i?1e3:800})}else if(s==="content")for(const o of b(t,e,"content"))h(o.text).toLowerCase().includes(i)&&c.push({...o,score:500});else for(const o of t||[]){const r=h(o?.title).toLowerCase();if(r.includes(i)){const a=g(o,e)[0];a&&c.push({...a,score:r===i?1e3:800});continue}for(const a of g(o,e))h(a.text).toLowerCase().includes(i)&&c.push({...a,score:500})}return k(c,e.limit)}function K(t){return String(t?.text||"").split(/\r?\n/).map(n=>{let e=n.trim();return!e||/^(agent|date|platform)\s*:/i.test(e)?"":/^(chat|meeting|summary|transcript)\s*:/i.test(e)?e.replace(/^[^:]+:\s*/i,""):(e=e.replace(/^---\s*[^-]+---$/i,""),e=e.replace(/^\[[^\]]+\]\s*[^:]{1,60}:\s*/i,""),e=e.replace(/^(user|assistant|system|you|speaker(?:\s*[-_#]?\s*\d+)?|[A-Z][\w .'’-]{0,40})\s*:\s*/i,""),e=e.replace(/^attached\s*:\s*/i,""),e)}).join(`
3
- `)}function Q(t){return Array.isArray(t?.meta?.terms)&&t.meta.terms.length?t.meta.terms:H(`${t?.title||""}
4
- ${K(t)}`,10)}function V(t){const n=t.sharedPeople||[],e=t.sharedTopics||[],s=t.sharedTitleTerms||[],i=[];return n.length&&i.push(`shares ${n.join(", ")}`),e.length&&i.push(`shared topics: ${e.join(", ")}`),s.length&&i.push(`similar title: ${s.join(", ")}`),i.join(" · ")||`relationship score ${t.weight||0}`}function et(t,n,e={}){const s=m(e.limit,8,1,30),i=w(t,e.scope||"all",e.includeMeetings!==!1),c=new Map(i.map(r=>[r.id,r]));return c.has(n)?A(i.map(r=>({id:r.id,title:r.title||r.id,platform:r.meta?.platform||r.type,startedAt:r.date||0,people:[],terms:Q(r)}))).relatedMeetings(n,{limit:s}).map(r=>{const a=c.get(r.id),u=r.sharedPeople||[];return{sourceId:r.id,type:a?.type||"",title:a?.title||r.id,date:a?.date||0,url:a?.url||"",weight:r.weight,shared:u,reason:V(r)}}):[]}function X(t,{query:n="",maxChars:e=12e3}={}){const s=m(e,12e3,1e3,5e4),i=[`History search results for: ${n||"(no query)"}`,'These are truncated excerpts, not the records. Before reporting details (action items, decisions, who said what, dates), read the full record: history_get_meeting with a meeting: id, history_get_source with any other id. Cite labels inline with <sup>[1]</sup> and add a bottom "Sources" list with labels/links/IDs.',""];let c=i.join(`
5
- `).length;for(const o of t||[]){const r=`[${o.sourceId}#${o.chunk}] ${o.title||o.sourceId}`,a=o.date?` · ${new Date(o.date).toLocaleString()}`:"",u=Number.isFinite(o.score)?` · score ${o.score.toFixed(2)}`:"",l=o.url?` · Open: [Open in ChatPanel](${o.url})`:"",f=`${r}${a}${u}${l}`,x=s<=1200?Math.min(120,Math.max(80,s-c-f.length-80)):Math.max(240,s-c-f.length-80),p=o.text.length>x?`${o.text.slice(0,x).trim()}...`:o.text,d=`${f}
1
+ import{bm25Search as A,buildGraph as E,buildIndex as H,tokenize as M,topTerms as F}from"./text-index.js";import{withoutOwnInstructions as $}from"./own-instructions.js";const C=1800,b=220,R=new Set("chat chats history source sources search result results local previous prior past meeting meetings meet meets call calls transcript transcripts recording recordings conversation conversations discuss discussed discussing find show list had have".split(/\s+/));function h(t){return String(t||"").replace(/\s+/g," ").trim()}function m(t,n,e,s){const i=Number(t);return Number.isFinite(i)?Math.max(e,Math.min(s,Math.floor(i))):n}function j(t){return String(t||"").toLowerCase()==="exact"?"exact":"best"}function y(t){const n=String(t||"").toLowerCase();return n==="title"||n==="name"?"title":n==="content"||n==="body"||n==="text"||n==="transcript"?"content":"all"}function w(t,n,e){const s=n==="meetings"||n==="chats"||n==="notes"?n:"all";return(t||[]).filter(i=>!e&&i.type==="meeting"?!1:s==="meetings"?i.type==="meeting":s==="chats"?i.type==="chat":s==="notes"?i.type==="note":i.type==="chat"||i.type==="meeting"||i.type==="note")}function g(t,{maxChunkChars:n=C,overlapChars:e=b}={}){const s=h($(t?.text));if(!t?.id||!t?.type||!s)return[];const i=m(n,C,400,8e3),c=m(e,b,0,Math.floor(i/2)),o=[];let r=0,a=0;for(;r<s.length;){let u=Math.min(s.length,r+i);if(u<s.length){const f=s.lastIndexOf(" ",u);f>r+Math.floor(i*.6)&&(u=f)}const l=s.slice(r,u).trim();if(l&&(o.push({id:`${t.id}#${a}`,sourceId:t.id,chunk:a,type:t.type,title:t.title||(t.type==="meeting"?"Meeting":t.type==="note"?"Note":"Chat"),date:t.date||0,text:l,url:t.url||"",meta:t.meta||{}}),a+=1),u>=s.length)break;r=Math.max(0,u-c)}return o}function et(t,n={}){return(t||[]).flatMap(e=>g(e,n))}function N(t,n){return y(n)==="content"&&t&&t.contentText!=null?{...t,text:t.contentText}:t}function T(t,n={},e="all"){return(t||[]).flatMap(s=>g(N(s,e),n))}function L(t){return/\b(?:1\s*[:x]\s*1|1\s*[-\s]*(?:on|to)\s*[-\s]*1|one\s*[-\s]*on\s*[-\s]*one|one\s*[-\s]*to\s*[-\s]*one)\b/i.test(String(t||""))}function D(t){return{terms:[...new Set(M(t).filter(e=>!R.has(e)))],directMeeting:L(t)}}function k(t,n){const e=String(n||"").toLowerCase();let s=0;for(const i of t||[])e.includes(i)&&(s+=1);return s}const O=16,v=12;function B(t,n){const e=n?.get(t);return e==null?1.5:e<=.15?.15:Math.min(e,3)}function P(t,n,e,s){if(!t||s==="content"||!n?.length)return 0;const i=String(t.title||"").toLowerCase(),c=Array.isArray(t.meta?.people)?t.meta.people.join(" ").toLowerCase():"";let o=0;for(const r of n){const a=B(r,e);i.includes(r)&&(o+=a*O),c&&c.includes(r)&&(o+=a*v)}return o}function z(t,n,e){if(!t||t.type!=="meeting"||e==="content")return 0;const s=n?.terms||[];if(!s.length&&!n?.directMeeting)return 0;const i=String(t.title||""),c=Array.isArray(t.meta?.people)?t.meta.people:[],o=c.join(" "),r=k(s,i),a=k(s,o);let u=r*45+a*28;return n?.directMeeting&&(L(i)&&(u+=80),r&&(u+=35),a&&(u+=25),a&&c.length>0&&c.length<=2&&(u+=70)),u}function _(t,n){const e=(t||[]).filter(l=>l?.sourceId).sort((l,f)=>f.score-l.score||(f.date||0)-(l.date||0)),s=e[0]?.score||0,i=s>0?s*.5:0,c=[],o=[],r=[],a=new Set,u=new Set;for(const l of e)a.has(l.sourceId)?u.has(l.sourceId)?r.push(l):o.push(l):(a.add(l.sourceId),l.score>=i?c.push(l):(u.add(l.sourceId),r.push(l)));return[...c,...o,...r].slice(0,n).map((l,f)=>({...l,rank:f+1}))}const q=45,U=.3;function Y(t,n=Date.now()){if(!t)return 1;const e=Math.max(0,(n-t)/864e5);return 1+U*Math.exp(-e/q)}function W(t,n={}){const e=w(t,n.scope||"all",n.includeMeetings!==!1),s=y(n.field),i=T(e,n,s),c=s==="title"?I(e,n).map(r=>({id:r.id,text:r.title})):i.map(r=>({id:r.id,text:s==="content"?r.text:`${r.title}
2
+ ${r.text}`})),o=new Map(i.map(r=>[r.id,r]));for(const r of I(e,n))o.set(r.id,r);return{idx:H(c),byId:o,field:s}}function G(t,n,e={}){const s=m(e.limit,8,1,30),i=h(n);if(!i||!t?.idx)return[];const{idx:c,byId:o,field:r}=t,a=i.toLowerCase(),u=M(a),l=D(i),f=A(c,i).map(x=>{const p=o.get(x.id);let d=x.score;const S=String(p?.title||"").toLowerCase();return r!=="content"&&(S===a?d+=80:S.includes(a)&&(d+=50)),d+=P(p,u,c.idf,r),d+=z(p,l,r),e.recency&&(d*=Y(p?.date,e.now)),{...p,score:d}});return _(f,s)}function nt(t,n,e={}){const s=j(e.mode),i=h(n);if(!i)return[];if(s==="exact"){const c=w(t,e.scope||"all",e.includeMeetings!==!1);return K(c,i,{...e,field:y(e.field),limit:m(e.limit,8,1,30)})}return G(W(t,e),n,e)}function I(t,n={}){return(t||[]).map(e=>g(e,n)[0]).filter(Boolean)}function K(t,n,e={}){const s=y(e.field),i=n.toLowerCase(),c=[];if(s==="title")for(const o of t||[]){const r=h(o?.title).toLowerCase();if(!r.includes(i))continue;const a=g(o,e)[0];a&&c.push({...a,score:r===i?1e3:800})}else if(s==="content")for(const o of T(t,e,"content"))h(o.text).toLowerCase().includes(i)&&c.push({...o,score:500});else for(const o of t||[]){const r=h(o?.title).toLowerCase();if(r.includes(i)){const a=g(o,e)[0];a&&c.push({...a,score:r===i?1e3:800});continue}for(const a of g(o,e))h(a.text).toLowerCase().includes(i)&&c.push({...a,score:500})}return _(c,e.limit)}function Q(t){return String(t?.text||"").split(/\r?\n/).map(n=>{let e=n.trim();return!e||/^(agent|date|platform)\s*:/i.test(e)?"":/^(chat|meeting|summary|transcript)\s*:/i.test(e)?e.replace(/^[^:]+:\s*/i,""):(e=e.replace(/^---\s*[^-]+---$/i,""),e=e.replace(/^\[[^\]]+\]\s*[^:]{1,60}:\s*/i,""),e=e.replace(/^(user|assistant|system|you|speaker(?:\s*[-_#]?\s*\d+)?|[A-Z][\w .'’-]{0,40})\s*:\s*/i,""),e=e.replace(/^attached\s*:\s*/i,""),e)}).join(`
3
+ `)}function V(t){return Array.isArray(t?.meta?.terms)&&t.meta.terms.length?t.meta.terms:F(`${t?.title||""}
4
+ ${Q(t)}`,10)}function X(t){const n=t.sharedPeople||[],e=t.sharedTopics||[],s=t.sharedTitleTerms||[],i=[];return n.length&&i.push(`shares ${n.join(", ")}`),e.length&&i.push(`shared topics: ${e.join(", ")}`),s.length&&i.push(`similar title: ${s.join(", ")}`),i.join(" · ")||`relationship score ${t.weight||0}`}function rt(t,n,e={}){const s=m(e.limit,8,1,30),i=w(t,e.scope||"all",e.includeMeetings!==!1),c=new Map(i.map(r=>[r.id,r]));return c.has(n)?E(i.map(r=>({id:r.id,title:r.title||r.id,platform:r.meta?.platform||r.type,startedAt:r.date||0,people:[],terms:V(r)}))).relatedMeetings(n,{limit:s}).map(r=>{const a=c.get(r.id),u=r.sharedPeople||[];return{sourceId:r.id,type:a?.type||"",title:a?.title||r.id,date:a?.date||0,url:a?.url||"",weight:r.weight,shared:u,reason:X(r)}}):[]}function Z(t,{query:n="",maxChars:e=12e3}={}){const s=m(e,12e3,1e3,5e4),i=[`History search results for: ${n||"(no query)"}`,'These are truncated excerpts, not the records. Before reporting details (action items, decisions, who said what, dates), read the full record: history_get_meeting with a meeting: id, history_get_source with any other id. Cite labels inline with <sup>[1]</sup> and add a bottom "Sources" list with labels/links/IDs.',""];let c=i.join(`
5
+ `).length;for(const o of t||[]){const r=`[${o.sourceId}#${o.chunk}] ${o.title||o.sourceId}`,a=o.date?` · ${new Date(o.date).toLocaleString()}`:"",u=Number.isFinite(o.score)?` · score ${o.score.toFixed(2)}`:"",l=o.url?` · Open: [Open in Chap](${o.url})`:"",f=`${r}${a}${u}${l}`,x=s<=1200?Math.min(120,Math.max(80,s-c-f.length-80)):Math.max(240,s-c-f.length-80),p=o.text.length>x?`${o.text.slice(0,x).trim()}...`:o.text,d=`${f}
6
6
  ${p}
7
7
  `;if(c+d.length>s&&i.length>3||(i.push(d),c+=d.length,c>=s))break}return(t||[]).length===0&&i.push("No matching local history sources were found."),i.join(`
8
- `).trim()}function nt(t,n,e={}){const s=new Set((n||[]).map(c=>c.sourceId)).size,i=X(n,{query:t,maxChars:e.maxChars});return{id:`history_rag_${Date.now()}`,kind:"history-rag",title:`History search · ${s} source${s===1?"":"s"}`,text:i,chars:i.length}}function rt(t,n,{maxChars:e=2e4}={}){const s=(t||[]).find(a=>a.id===n);if(!s)return{sourceId:n,found:!1,text:""};const i=m(e,2e4,1e3,1e5),c=h(s.text),o=c.length>i,r=o?`${c.slice(0,i).trim()}...`:c;return{sourceId:n,type:s.type,title:s.title||n,date:s.date||0,url:s.url||"",found:!0,truncated:o,text:r}}export{J as buildHistoryChunks,nt as buildHistoryRagAttachment,Y as buildSearchIndex,g as chunkHistorySource,X as formatHistoryResults,rt as getHistorySource,et as relatedHistorySources,W as runSearch,tt as searchHistorySources};
8
+ `).trim()}function it(t,n,e={}){const s=new Set((n||[]).map(c=>c.sourceId)).size,i=Z(n,{query:t,maxChars:e.maxChars});return{id:`history_rag_${Date.now()}`,kind:"history-rag",title:`History search · ${s} source${s===1?"":"s"}`,text:i,chars:i.length}}function st(t,n,{maxChars:e=2e4}={}){const s=(t||[]).find(a=>a.id===n);if(!s)return{sourceId:n,found:!1,text:""};const i=m(e,2e4,1e3,1e5),c=h($(s.text)),o=c.length>i,r=o?`${c.slice(0,i).trim()}...`:c;return{sourceId:n,type:s.type,title:s.title||n,date:s.date||0,url:s.url||"",found:!0,truncated:o,text:r}}export{et as buildHistoryChunks,it as buildHistoryRagAttachment,W as buildSearchIndex,g as chunkHistorySource,Z as formatHistoryResults,st as getHistorySource,rt as relatedHistorySources,G as runSearch,nt as searchHistorySources};
package/identity.js ADDED
@@ -0,0 +1 @@
1
+ import{isSmallWindow as a}from"./context-window.js";const i=/\bwho (?:are|r) (?:you|u)\b|\bwhat (?:are|r) (?:you|u)\s*[?.!]*\s*$|\byour name\b|\bwhat(?:'s| is) your name\b|\b(?:which|what) (?:model|llm|ai)(?: are you| is this| am i (?:talking|speaking) to| do you (?:use|run)| powers you|\s*[?.!]*\s*$)|\bare you (?:an? )?(?:ai|bot|robot|human|person|chat ?gpt|gpt|claude|gemini|siri|apple intelligence)\b|\bintroduce yourself\b|\bwho (?:made|built|created) you\b/i;function r(e){return i.test(String(e||""))}function s({name:e="Chap",model:t="",window:n=0}={}){return a(n)?`Your name is ${e}.`:`You are ${e}, the assistant in the Chap app. When asked who you are, you are ${e}; you may add that you are running on ${t||"your model"} if asked which model.`}function h({name:e="Chap",model:t="",question:n="",window:o=0}={}){return!a(o)||!r(n)?"":`(You are ${e}, the assistant in the Chap app${t?`, running on ${t}`:""}. Say so in a sentence.)`}export{r as asksIdentity,h as identityHint,s as identitySystem};