@chatpanel/events 0.161.2 → 0.189.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/events",
3
- "version": "0.161.2",
3
+ "version": "0.189.1",
4
4
  "description": "The canonical ChatPanel event-log and capability contracts — typed durable facts, clock-free deterministic linearization, schema upcasting, and the invariants the replay harness asserts. Pure, dependency-free ESM shared by the ChatPanel extension, gateway and bridge.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -11,10 +11,13 @@
11
11
  "./agent.js": "./agent.js",
12
12
  "./attribution.js": "./attribution.js",
13
13
  "./backup-envelope.js": "./backup-envelope.js",
14
+ "./blob-envelope.js": "./blob-envelope.js",
15
+ "./bytes-b64.js": "./bytes-b64.js",
14
16
  "./backup-records.js": "./backup-records.js",
15
17
  "./budget.js": "./budget.js",
16
18
  "./capability.js": "./capability.js",
17
19
  "./capability-endpoints.js": "./capability-endpoints.js",
20
+ "./capability-uses.js": "./capability-uses.js",
18
21
  "./capability-client.js": "./capability-client.js",
19
22
  "./capability-adapters.js": "./capability-adapters.js",
20
23
  "./capability-providers.js": "./capability-providers.js",
@@ -23,8 +26,13 @@
23
26
  "./plan.js": "./plan.js",
24
27
  "./plan-executor.js": "./plan-executor.js",
25
28
  "./model-roles.js": "./model-roles.js",
29
+ "./model-entries.js": "./model-entries.js",
30
+ "./model-fusion.js": "./model-fusion.js",
31
+ "./harness-cards.js": "./harness-cards.js",
26
32
  "./citations.js": "./citations.js",
27
33
  "./cloudevents.js": "./cloudevents.js",
34
+ "./event-sync.js": "./event-sync.js",
35
+ "./event-stats.js": "./event-stats.js",
28
36
  "./client-prefs.js": "./client-prefs.js",
29
37
  "./composer-chips.js": "./composer-chips.js",
30
38
  "./settings-registry.js": "./settings-registry.js",
@@ -57,6 +65,7 @@
57
65
  "./manifest.js": "./manifest.js",
58
66
  "./markdown-authoring.js": "./markdown-authoring.js",
59
67
  "./markdown-render.js": "./markdown-render.js",
68
+ "./note-images.js": "./note-images.js",
60
69
  "./sideline.js": "./sideline.js",
61
70
  "./mcp-client.js": "./mcp-client.js",
62
71
  "./mcp-config-import.js": "./mcp-config-import.js",
@@ -72,6 +81,8 @@
72
81
  "./meeting-analyzers.js": "./meeting-analyzers.js",
73
82
  "./meeting-insights.js": "./meeting-insights.js",
74
83
  "./meeting-shape.js": "./meeting-shape.js",
84
+ "./meeting-speakers.js": "./meeting-speakers.js",
85
+ "./meeting-speakers-typed.js": "./meeting-speakers-typed.js",
75
86
  "./meeting-text.js": "./meeting-text.js",
76
87
  "./memory.js": "./memory.js",
77
88
  "./memory-tool.js": "./memory-tool.js",
@@ -105,6 +116,7 @@
105
116
  "./registry.js": "./registry.js",
106
117
  "./route-graph.js": "./route-graph.js",
107
118
  "./route-strategies.js": "./route-strategies.js",
119
+ "./route-decider.js": "./route-decider.js",
108
120
  "./router.js": "./router.js",
109
121
  "./rrf.js": "./rrf.js",
110
122
  "./rules.js": "./rules.js",
@@ -162,6 +174,7 @@
162
174
  "./tool-hints.js": "./tool-hints.js",
163
175
  "./tool-need.js": "./tool-need.js",
164
176
  "./tool-result.js": "./tool-result.js",
177
+ "./agent-permission.js": "./agent-permission.js",
165
178
  "./tool-loop-guard.js": "./tool-loop-guard.js",
166
179
  "./tool-round.js": "./tool-round.js",
167
180
  "./tool-schema.js": "./tool-schema.js",
@@ -176,6 +189,8 @@
176
189
  "./view.js": "./view.js",
177
190
  "./voice-intents.js": "./voice-intents.js",
178
191
  "./voice-speaker.js": "./voice-speaker.js",
192
+ "./voice-channels.js": "./voice-channels.js",
193
+ "./voice-scribe.js": "./voice-scribe.js",
179
194
  "./voice-loop.js": "./voice-loop.js",
180
195
  "./voice-vad.js": "./voice-vad.js",
181
196
  "./voice-sample.js": "./voice-sample.js",
@@ -207,10 +222,13 @@
207
222
  "agent.js",
208
223
  "attribution.js",
209
224
  "backup-envelope.js",
225
+ "blob-envelope.js",
226
+ "bytes-b64.js",
210
227
  "backup-records.js",
211
228
  "budget.js",
212
229
  "capability.js",
213
230
  "capability-endpoints.js",
231
+ "capability-uses.js",
214
232
  "capability-client.js",
215
233
  "capability-adapters.js",
216
234
  "capability-providers.js",
@@ -219,6 +237,8 @@
219
237
  "plan.js",
220
238
  "plan-executor.js",
221
239
  "model-roles.js",
240
+ "model-entries.js",
241
+ "harness-cards.js",
222
242
  "citations.js",
223
243
  "cloudevents.js",
224
244
  "client-prefs.js",
@@ -238,6 +258,8 @@
238
258
  "engine.js",
239
259
  "entity.js",
240
260
  "event.js",
261
+ "event-sync.js",
262
+ "event-stats.js",
241
263
  "extraction.js",
242
264
  "failover.js",
243
265
  "gateway-dests.js",
@@ -254,6 +276,7 @@
254
276
  "manifest.js",
255
277
  "markdown-authoring.js",
256
278
  "markdown-render.js",
279
+ "note-images.js",
257
280
  "sideline.js",
258
281
  "mcp-client.js",
259
282
  "mcp-config-import.js",
@@ -264,11 +287,14 @@
264
287
  "mcp-launcher.js",
265
288
  "mcp-oauth.js",
266
289
  "mcp-signin.js",
290
+ "model-fusion.js",
267
291
  "model-registry.js",
268
292
  "media-transcript.js",
269
293
  "meeting-analyzers.js",
270
294
  "meeting-insights.js",
271
295
  "meeting-shape.js",
296
+ "meeting-speakers.js",
297
+ "meeting-speakers-typed.js",
272
298
  "meeting-text.js",
273
299
  "memory.js",
274
300
  "memory-tool.js",
@@ -308,6 +334,7 @@
308
334
  "registry.js",
309
335
  "route-graph.js",
310
336
  "route-strategies.js",
337
+ "route-decider.js",
311
338
  "router.js",
312
339
  "rrf.js",
313
340
  "rules.js",
@@ -365,6 +392,7 @@
365
392
  "tool-hints.js",
366
393
  "tool-need.js",
367
394
  "tool-result.js",
395
+ "agent-permission.js",
368
396
  "tool-loop-guard.js",
369
397
  "tool-round.js",
370
398
  "tool-schema.js",
@@ -379,6 +407,8 @@
379
407
  "view.js",
380
408
  "voice-intents.js",
381
409
  "voice-speaker.js",
410
+ "voice-channels.js",
411
+ "voice-scribe.js",
382
412
  "voice-loop.js",
383
413
  "voice-vad.js",
384
414
  "voice-sample.js",
@@ -0,0 +1,6 @@
1
+ import{defineRouteStrategy as q}from"./router.js";function x(e){const l=Number.isFinite(e.quality)?`quality ${e.quality.toFixed(2)}`:"quality unknown",a=e.costPer1k===0?"free":`cost ${e.costPer1k}`,i=Number.isFinite(e.latencyMs)?`~${e.latencyMs} ms to first token`:"",s=e.window?`window ${Math.round(e.window/1e3)}k`:"",n=e.reach==="device"?"on this device":e.reach==="trusted"?"on a trusted host":"a third party",$=e.classUsed==="A"?"a coding agent with its own loop":e.classUsed==="L"?"a local model":"an API model",f=(e.capabilities||[]).length?`can: ${e.capabilities.join(", ")}`:"no declared abilities",r=[e.rateLimited?"rate limited now":"",e.available===!1?"unavailable":""].filter(Boolean).join(", ");return[e.label||e.id,$,n,f,l,a,i,s,r].filter(Boolean).join(" · ")}function v(e={},{text:l=!1}={}){const a=e.signals||{},i=[];i.push(`Task: ${a.smalltalk?"small talk":a.code?"coding":"a question"}; complexity ${a.complexity||"unknown"}; modality ${a.modality||"text"}; about ${a.approxTokens||0} tokens${a.nonLatin?"; non-Latin script":""}.`),a.reference&&i.push(`Material attached by reference: ${a.reference.count} item(s), ${a.reference.pages||0} pages.`),(e.capabilities||[]).length&&i.push(`Needs: ${e.capabilities.join(", ")}.`),e.minQuality&&i.push(`Quality floor ${e.minQuality}.`),e.reach&&e.reach!=="any"&&i.push(`May reach: ${e.reach} only.`),e.prefer&&i.push(`Prefer: ${e.prefer}.`);const s=l&&e.requestText?String(e.requestText).trim().slice(-600):"";return s&&i.push(`The request ends: "${s}"`),i.join(`
2
+ `)}function F({decide:e,rerank:l=null,shortlist:a=6,text:i=!1,timeoutMs:s=4e3}={}){if(typeof e!="function")throw new Error("deciderStrategy: decide is required");return q({id:"decider",label:"Decision model",classUsed:"M",timeoutMs:s,decide:async(n,$)=>{if(!Array.isArray(n)||n.length<2)return null;const f=v($,{text:i}),r=n.map(t=>({id:t.id,card:x(t)})),p=[];let h=r;if(typeof l=="function")try{const t=await l({query:f,documents:r.map(d=>d.card),top_n:r.length}),c=(t?.results||[]).map(d=>r[d.index]).filter(Boolean);c.length&&(h=[...c,...r.filter(d=>!c.includes(d))],p.push(`reranker (${t.model||"rerank"}) ordered: ${h.slice(0,a).map(d=>d.id).join(" > ")}`))}catch(t){p.push(`reranker did not answer (${t?.message||t}); the score's order stands`)}const y=h.slice(0,Math.max(2,a)),g={state:`${f}
3
+
4
+ Candidates:
5
+ ${y.map(t=>`- ${t.id}: ${t.card}`).join(`
6
+ `)}`,questions:{model:{type:"choice",instructions:"Which candidate should answer this task? Weigh what the task needs against each card: quality for hard work, speed and cost for easy work, and never a candidate that lacks an ability the task needs.",options:y.map(t=>({value:t.id,describe:t.card}))}},budgetMs:s},k=await e(g),o=k?.answers?.model;if(!o||typeof o.value!="string")return null;const u=y.find(t=>t.id===o.value);if(!u)return null;const b=[...o.options||[]].sort((t,c)=>(c.p||0)-(t.p||0)),w=b.find(t=>t.value!==o.value);p.push(`decision model (${k.model||"decide"}) picked ${u.id}${Number.isFinite(o.p)?` at ${(o.p*100).toFixed(0)}%`:""}${w?`, then ${w.value} at ${((w.p||0)*100).toFixed(0)}%`:""}${k.calibrated===!1?" (not a calibrated probability)":""}`),n[0]&&n[0].id!==u.id&&p.push(`the score would have picked ${n[0].id}`);const m=b.map(t=>t.value).filter(t=>t!==u.id&&y.some(c=>c.id===t));return{ranked:[u.id,...m,...h.map(t=>t.id).filter(t=>t!==u.id&&!m.includes(t))],why:p}}})}export{x as candidateCard,F as deciderStrategy,v as taskBrief};
package/router.js CHANGED
@@ -1,2 +1,2 @@
1
- class k extends Error{constructor(s,l){super(l),this.name="RouterError",this.code=s}}import{REACH as re,reachRank as ie}from"./reach.js";import{REACH as C,reachRank as F}from"./reach.js";function W({id:t,label:s,reach:l="any",classUsed:h="C",capabilities:d=[],costPer1k:y=1,latencyMs:c=1e3,load:a=0,available:r=!0,rateLimited:i=!1,observedLatencyMs:n=null,quality:f=null,model:u="",providerRank:g=50,orderPinned:w=!1}){if(!t)throw new k("BAD_MODEL","model.id required");if(!C.includes(l))throw new k("BAD_MODEL",`model '${t}': unknown reach '${l}'`);return Object.freeze({id:t,label:s||t,reach:l,classUsed:h,model:u,capabilities:[...d],costPer1k:y,latencyMs:Number.isFinite(n)?n:c,declaredLatencyMs:c,observedLatencyMs:n,load:a,available:r,rateLimited:i,providerRank:g,orderPinned:!!w,quality:f})}function G({id:t,label:s,stage:l,priority:h=100,run:d,requiredFor:y=null}){if(!t)throw new k("BAD_MIDDLEWARE","middleware.id required");if(!["request","response"].includes(l))throw new k("BAD_MIDDLEWARE",`middleware '${t}': stage must be request or response`);if(typeof d!="function")throw new k("BAD_MIDDLEWARE",`middleware '${t}': run required`);return Object.freeze({id:t,label:s||t,stage:l,priority:h,run:d,requiredFor:y})}function H({id:t,label:s,classUsed:l="R",timeoutMs:h=0,decide:d}){if(!t)throw new k("BAD_STRATEGY","strategy.id required");if(typeof d!="function")throw new k("BAD_STRATEGY",`strategy '${t}': decide required`);return Object.freeze({id:t,label:s||t,classUsed:l,timeoutMs:h,decide:d})}const T=.1,L=5,j=Object.freeze({device:.7,trusted:.85,any:1});function P(t){return String(t?.model||t?.label||"").toLowerCase().replace(/^[^/]+\//,"").replace(/[:@].*$/,"").replace(/[^a-z0-9.]+/g,"")}function Y(t={}){const s=String(t.text||(t.messages||[]).map(a=>a?.content||"").join(`
2
- `)||""),l=s.length,h=!!(t.images?.length||t.attachments?.some?.(a=>/^image\//.test(a?.type||""))),d=!!t.audio||!!t.attachments?.some?.(a=>/^audio\//.test(a?.type||"")),c=(t.attachments||[...t.messages||[]].reverse().find(a=>a?.role==="user")?.attachments||[]).filter(a=>a?.kind==="path");return{reference:c.length?{count:c.length,folders:c.filter(a=>a.isDir).length,documents:c.filter(a=>a.isDir===!1).length,pages:c.reduce((a,r)=>a+(Number(r.pages)||0),0)}:null,approxTokens:Math.round(l/4),modality:d?"audio":h?"vision":"text",code:/```/.test(s)||l>80&&/\bfunction\b|\bclass\b|=>|;\s*$|\bdef\b|\bimport\b|\bconst\b/m.test(s)||/\b(write|fix|debug|refactor|implement|optimi[sz]e|review|explain|generate|add|update|port|migrate)\b[^.?!]{0,60}\b(code|function|method|class|script|bug|regex|query|unit ?test|module|component|endpoint|snippet|compiler?|stack ?trace|typescript|javascript|python|rust|golang|sql|css|html)\b/i.test(s),complexity:l>4e3||/```/.test(s)||l>=200&&/\bstep by step\b|\bplan\b|\brefactor\b|\bmigrate\b|\banalyse|\banalyze/i.test(s)?"high":l<200?"low":"medium",nonLatin:/[^\u0000-\u024F\u2000-\u206F]/.test(s),smalltalk:l<100&&!/```/.test(s)&&!/\b(draw|click|open|fill|read|find|search|edit|write|create|update|delete|run|fix|change|add|remove|select|scroll|extract|summar\w*|analy\w*|check|review|list|show|go to|navigate|my|mine|this page|here|it|that)\b/i.test(s)&&!/\b(explain|describe|define|compare|translate|why|debug|refactor|implement|improve|optimi[sz]e|convert|calculate|generate|draft|rename|build|test|install|deploy|design|plan)\b/i.test(s)&&!/\bhow\s+(do|does|did|can|could|should|would|to|much|many|long)\b/i.test(s),chars:l}}const S=(t,s)=>`${t} ${s}${t===1?"":"s"}`;function B(t){const s=[];return t.folders&&s.push(S(t.folders,"folder")),t.documents&&s.push(`${S(t.documents,"document")}${t.pages?` (${t.pages} pages)`:""}`),s.length?s.join(" and "):S(t.count,"path")}function V(t={},{structured:s=!1,hasTools:l=!1,pageTools:h=!1,background:d=!1,minWindow:y=0}={}){const c=new Set;let a=0;const r=[];y>0&&r.push(`the turn needs a ${Math.round(y/1e3)}k window`),l&&(c.add("tools"),r.push("the turn carries tools")),t.modality==="vision"&&(c.add("vision"),r.push("the request includes an image")),h&&!t.smalltalk&&(c.add("tools"),a=Math.max(a,.55),r.push("driving a page needs exact actions")),t.approxTokens>2e4&&(c.add("long-context"),r.push("the request is large")),t.reference?.count&&(c.add("tools"),a=Math.max(a,.55),r.push(`${B(t.reference)} attached by reference — read through the files tool`)),t.code&&(c.add("coding"),r.push("the request contains code")),s&&!t.smalltalk&&(c.add("tools"),a=Math.max(a,.55),r.push("it must produce an exact structured payload")),t.complexity==="high"&&!d&&(a=Math.max(a,.55),r.push("the task is complex"));const i=t.smalltalk&&!t.reference?.count?[...c]:[...c].filter(n=>n!=="tools");return{required:[...c],negotiable:i,minQuality:a,why:r,minWindow:Math.max(0,Number(y)||0)}}function K(t={},{structured:s=!1,minQuality:l=0,hasTools:h=!1,background:d=!1}={}){return d?{prefer:"cost",why:"background work — spend as little as possible"}:s||t.complexity==="high"||t.code||t.modality==="vision"?{prefer:"quality",why:"the task is exact or hard — get it right rather than quick"}:t.smalltalk&&!h&&!l?{prefer:"latency",why:"nothing to look up — answer fast"}:{prefer:"balanced",why:"no reason to favour speed or quality"}}function E(t){return t?.orderPinned&&Number.isFinite(t.providerRank)?t.providerRank:1/0}const Q=.25,U=.25;function J(t=[],s={}){const l=i=>!!s.model&&P(i)===P(s);let h=[...t];if(s.reason==="gone"){const i=h.filter(n=>!l(n));i.length&&(h=i)}const d=i=>Number.isFinite(i.quality)?i.quality:.5,y=i=>(s.capabilities||[]).every(n=>(i.capabilities||[]).includes(n)),c=i=>!s.classUsed||i.classUsed===s.classUsed,a=Number.isFinite(s.quality)?s.quality:null;if(a!==null){const i=n=>l(n)?-1:Math.abs(d(n)-a)+(c(n)?0:Q)+(y(n)?0:U);return h.map(n=>({m:n,d:i(n)})).sort((n,f)=>n.d-f.d||E(n.m)-E(f.m)||n.m.costPer1k-f.m.costPer1k||String(n.m.id).localeCompare(String(f.m.id))).map(n=>n.m)}const r=i=>l(i)?0:c(i)&&y(i)?1:c(i)?2:y(i)?3:4;return h.sort((i,n)=>r(i)-r(n)||d(n)-d(i)||E(i)-E(n)||i.costPer1k-n.costPer1k)}function X(t,s={}){const l=String(t||""),h=String(s?.action||""),d=`${l}.${h}`;return/screenshot|marked_screenshot|read_canvas|sense_canvas/.test(d)?{required:["vision"],why:"this step reads an image"}:/structured_insert|sheet_write|fill_form|input_sequence|draw_path/.test(d)?{required:["tools"],minQuality:.55,why:"this step writes an exact payload"}:{required:l?["tools"]:[],why:""}}function Z({models:t=[],middleware:s=[],strategies:l=[],admit:h=null}={}){const d=[...t],y=[...s],c=[...l],a=r=>y.filter(i=>i.stage===r&&(!h||h(i))).sort((i,n)=>r==="request"?i.priority-n.priority:n.priority-i.priority);return{addModel(r){return d.push(r),()=>{const i=d.indexOf(r);i>=0&&d.splice(i,1)}},use(r){return y.push(r),()=>{const i=y.indexOf(r);i>=0&&y.splice(i,1)}},addStrategy(r){return c.push(r),()=>{const i=c.indexOf(r);i>=0&&c.splice(i,1)}},models:()=>[...d],middleware:()=>[...y],strategies:()=>[...c],route(r={}){const i=C.includes(r.reach)?r.reach:"any",n=r.capabilities||[],f=r.requirementReasons||[],u=[],g=d.filter(e=>{if(!e.available)return u.push({id:e.id,why:"unavailable"}),!1;if(h&&!h(e))return u.push({id:e.id,why:"disabled"}),!1;if(F(e.reach)>F(i))return u.push({id:e.id,why:`reach '${e.reach}' exceeds '${i}'`}),!1;const o=n.filter(x=>!e.capabilities.includes(x));if(o.length)return u.push({id:e.id,why:`missing ${o.join(", ")}`}),!1;if(r.minWindow>0&&Number(e.window)>0&&Number(e.window)<r.minWindow)return u.push({id:e.id,why:`a ${Math.round(e.window/1e3)}k window under the ${Math.round(r.minWindow/1e3)}k this turn needs`}),!1;if(r.maxLatencyMs>0&&e.latencyMs>r.maxLatencyMs)return u.push({id:e.id,why:`${e.latencyMs}ms exceeds the ${r.maxLatencyMs}ms deadline`}),!1;if(r.maxCostPer1k>=0&&r.maxCostPer1k!==void 0&&e.costPer1k>r.maxCostPer1k)return u.push({id:e.id,why:`costs ${e.costPer1k} over the ${r.maxCostPer1k} budget`}),!1;if(e.rateLimited)return u.push({id:e.id,why:"rate limited"}),!1;if(r.exclude?.includes?.(e.id))return u.push({id:e.id,why:"already failed this request"}),!1;if(r.minQuality>0){const x=Number.isFinite(e.quality)?e.quality:.5;if(x<r.minQuality)return u.push({id:e.id,why:`below the quality this task needs (${x} < ${r.minQuality})`}),!1}return!0});if(!g.length){if(r.minQuality>0){const e=this.route({...r,minQuality:0});if(e.model)return{...e,relaxed:!0,reasons:[...e.reasons,`no model met the quality this task needs (${r.minQuality}) — used the best available instead`]}}if(r.negotiable?.length){const e=(r.capabilities||[]).filter(x=>!r.negotiable.includes(x)),o=this.route({...r,minQuality:0,capabilities:e,negotiable:[]});if(o.model)return{...o,relaxed:!0,reasons:[...o.reasons,`no model offers ${r.negotiable.join(", ")} — used one without it, which may do this task poorly`]}}return{model:null,reasons:["no candidate satisfies the constraints"],constraints:f,rejected:u}}const w=r.prefer||"balanced",v=e=>{const o=1+Math.max(0,Math.min(1,e.load)),x=Number.isFinite(e.quality)?Math.max(.1,e.quality):.5,O=j[e.reach]??1;return w==="latency"?e.latencyMs*o*O:w==="cost"?e.costPer1k*o*O:w==="quality"?o/x:(e.latencyMs/1e3+e.costPer1k*L)*o*O/x},$=new Map,b=e=>($.has(e)||$.set(e,v(e)),$.get(e)),m=(e,o)=>e.providerRank-o.providerRank||b(e)-b(o)||e.id.localeCompare(o.id),p=(e,o)=>b(e)-b(o)||e.providerRank-o.providerRank||e.id.localeCompare(o.id),A=new Map;for(const e of g){const o=P(e)||`#${e.id}`;A.has(o)||A.set(o,[]),A.get(o).push(e)}const D=[...A.values()].map(e=>[...e].sort(e.some(o=>o.orderPinned)?m:p));D.sort((e,o)=>b(e[0])-b(o[0])||m(e[0],o[0]));const M=[];for(const e of D){const o=M[M.length-1],x=o?b(o[0][0]):0;o&&b(e[0])<=x*(1+T)?o.push(e):M.push([e])}for(const e of M)e.sort((o,x)=>m(o[0],x[0]));let q=M.flat(2);const R=w==="balanced"?q.filter(e=>e.orderPinned).sort((e,o)=>e.providerRank-o.providerRank)[0]:null;R&&(q=[R,...q.filter(e=>e!==R)]);const I=M[0]?.length>1,N=(M[0]||[]).flat().length,_=q[0];return{model:_,eligible:q,constraints:f,strategy:R?"declared-default":"default-score",reasons:[`reach '${_.reach}' within '${i}'`,n.length?`has ${n.join(", ")}`:"no special capability needed",R?`your default (Order ${_.providerRank}) — nothing about this turn asked for anything else`:I?`order ${_.providerRank} broke a ${N}-way tie by ${w}, of ${q.length} eligible`:`best by ${w} (${q.length} eligible)`],rejected:u,runnersUp:q.slice(1).map(e=>e.id)}},async routeWith(r={},i={}){const n=this.route(r);if(!n.model||!c.length)return n;const f=new Map(n.eligible.map(u=>[u.id,u]));for(const u of c){if(h&&!h(u))continue;let g=null;try{const m=u.decide([...n.eligible],r,i);g=u.timeoutMs>0?await Promise.race([m,new Promise(p=>setTimeout(()=>p(null),u.timeoutMs))]):await m}catch{g=null}if(!g)continue;const w=(Array.isArray(g)?g:[g]).map(m=>typeof m=="string"?f.get(m):f.get(m?.id)).filter(Boolean),v=(Array.isArray(g)?g:[g]).length-w.length;if(!w.length)continue;const $=n.eligible.filter(m=>!w.includes(m)),b=[...w,...$];return{...n,model:w[0],eligible:b,strategy:u.id,runnersUp:b.slice(1).map(m=>m.id),reasons:[...n.reasons.slice(0,-1),`chosen by '${u.id}' (class ${u.classUsed}) from ${n.eligible.length} eligible`,...v>0?[`${v} suggestion(s) ignored — not eligible under the constraints`]:[]]}}return n},async run(r,{dispatch:i,need:n={}}={}){if(typeof i!="function")throw new k("NO_DISPATCH","run needs a dispatch function");const f=await this.routeWith(n,{request:r});if(!f.model)throw new k("NO_ROUTE",f.reasons[0]);const u=p=>!p.requiredFor||p.requiredFor(f.model,n),g=y.filter(p=>p.requiredFor&&p.requiredFor(f.model,n)),w=new Set(a("request").concat(a("response")).map(p=>p.id)),v=g.filter(p=>!w.has(p.id));if(v.length)throw new k("MISSING_REQUIRED",`route to '${f.model.id}' requires ${v.map(p=>p.id).join(", ")}, which is not active`);const $={model:f.model,need:n,decision:f};let b=r;for(const p of a("request"))u(p)&&(b=await p.run(b,$)??b);let m=await i(b,$);for(const p of a("response"))u(p)&&(m=await p.run(m,$)??m);return{answer:m,decision:f}}}}export{U as FAILOVER_CAPABILITY_GAP,Q as FAILOVER_CLASS_GAP,re as REACH,k as RouterError,Z as createModelRouter,G as defineMiddleware,W as defineModel,H as defineRouteStrategy,J as failoverOrder,E as pinnedOrderOf,K as preferenceFor,ie as reachRank,V as requirementsFor,X as requirementsForStep,P as sameModelKey,Y as signalsFrom};
1
+ class q extends Error{constructor(s,l){super(l),this.name="RouterError",this.code=s}}import{REACH as re,reachRank as ie}from"./reach.js";import{REACH as C,reachRank as F}from"./reach.js";function W({id:t,label:s,reach:l="any",classUsed:h="C",capabilities:d=[],costPer1k:y=1,latencyMs:c=1e3,load:a=0,available:r=!0,rateLimited:i=!1,observedLatencyMs:n=null,quality:p=null,model:u="",providerRank:g=50,orderPinned:b=!1,window:v=0}){if(!t)throw new q("BAD_MODEL","model.id required");if(!C.includes(l))throw new q("BAD_MODEL",`model '${t}': unknown reach '${l}'`);return Object.freeze({id:t,label:s||t,reach:l,classUsed:h,model:u,capabilities:[...d],costPer1k:y,latencyMs:Number.isFinite(n)?n:c,declaredLatencyMs:c,observedLatencyMs:n,load:a,available:r,rateLimited:i,providerRank:g,orderPinned:!!b,quality:p,window:Number(v)>0?Number(v):0})}function G({id:t,label:s,stage:l,priority:h=100,run:d,requiredFor:y=null}){if(!t)throw new q("BAD_MIDDLEWARE","middleware.id required");if(!["request","response"].includes(l))throw new q("BAD_MIDDLEWARE",`middleware '${t}': stage must be request or response`);if(typeof d!="function")throw new q("BAD_MIDDLEWARE",`middleware '${t}': run required`);return Object.freeze({id:t,label:s||t,stage:l,priority:h,run:d,requiredFor:y})}function H({id:t,label:s,classUsed:l="R",timeoutMs:h=0,decide:d}){if(!t)throw new q("BAD_STRATEGY","strategy.id required");if(typeof d!="function")throw new q("BAD_STRATEGY",`strategy '${t}': decide required`);return Object.freeze({id:t,label:s||t,classUsed:l,timeoutMs:h,decide:d})}const T=.1,L=5,j=Object.freeze({device:.7,trusted:.85,any:1});function S(t){return String(t?.model||t?.label||"").toLowerCase().replace(/^[^/]+\//,"").replace(/[:@].*$/,"").replace(/[^a-z0-9.]+/g,"")}function Y(t={}){const s=String(t.text||(t.messages||[]).map(a=>a?.content||"").join(`
2
+ `)||""),l=s.length,h=!!(t.images?.length||t.attachments?.some?.(a=>/^image\//.test(a?.type||""))),d=!!t.audio||!!t.attachments?.some?.(a=>/^audio\//.test(a?.type||"")),c=(t.attachments||[...t.messages||[]].reverse().find(a=>a?.role==="user")?.attachments||[]).filter(a=>a?.kind==="path");return{reference:c.length?{count:c.length,folders:c.filter(a=>a.isDir).length,documents:c.filter(a=>a.isDir===!1).length,pages:c.reduce((a,r)=>a+(Number(r.pages)||0),0)}:null,approxTokens:Math.round(l/4),modality:d?"audio":h?"vision":"text",code:/```/.test(s)||l>80&&/\bfunction\b|\bclass\b|=>|;\s*$|\bdef\b|\bimport\b|\bconst\b/m.test(s)||/\b(write|fix|debug|refactor|implement|optimi[sz]e|review|explain|generate|add|update|port|migrate)\b[^.?!]{0,60}\b(code|function|method|class|script|bug|regex|query|unit ?test|module|component|endpoint|snippet|compiler?|stack ?trace|typescript|javascript|python|rust|golang|sql|css|html)\b/i.test(s),complexity:l>4e3||/```/.test(s)||l>=200&&/\bstep by step\b|\bplan\b|\brefactor\b|\bmigrate\b|\banalyse|\banalyze/i.test(s)?"high":l<200?"low":"medium",nonLatin:/[^\u0000-\u024F\u2000-\u206F]/.test(s),smalltalk:l<100&&!/```/.test(s)&&!/\b(draw|click|open|fill|read|find|search|edit|write|create|update|delete|run|fix|change|add|remove|select|scroll|extract|summar\w*|analy\w*|check|review|list|show|go to|navigate|my|mine|this page|here|it|that)\b/i.test(s)&&!/\b(explain|describe|define|compare|translate|why|debug|refactor|implement|improve|optimi[sz]e|convert|calculate|generate|draft|rename|build|test|install|deploy|design|plan)\b/i.test(s)&&!/\bhow\s+(do|does|did|can|could|should|would|to|much|many|long)\b/i.test(s),chars:l}}const D=(t,s)=>`${t} ${s}${t===1?"":"s"}`;function B(t){const s=[];return t.folders&&s.push(D(t.folders,"folder")),t.documents&&s.push(`${D(t.documents,"document")}${t.pages?` (${t.pages} pages)`:""}`),s.length?s.join(" and "):D(t.count,"path")}function V(t={},{structured:s=!1,hasTools:l=!1,pageTools:h=!1,background:d=!1,minWindow:y=0}={}){const c=new Set;let a=0;const r=[];y>0&&r.push(`the turn needs a ${Math.round(y/1e3)}k window`),l&&(c.add("tools"),r.push("the turn carries tools")),t.modality==="vision"&&(c.add("vision"),r.push("the request includes an image")),h&&!t.smalltalk&&(c.add("tools"),a=Math.max(a,.55),r.push("driving a page needs exact actions")),t.approxTokens>2e4&&(c.add("long-context"),r.push("the request is large")),t.reference?.count&&(c.add("tools"),a=Math.max(a,.55),r.push(`${B(t.reference)} attached by reference — read through the files tool`)),t.code&&(c.add("coding"),r.push("the request contains code")),s&&!t.smalltalk&&(c.add("tools"),a=Math.max(a,.55),r.push("it must produce an exact structured payload")),t.complexity==="high"&&!d&&(a=Math.max(a,.55),r.push("the task is complex"));const i=t.smalltalk&&!t.reference?.count?[...c]:[...c].filter(n=>n!=="tools");return{required:[...c],negotiable:i,minQuality:a,why:r,minWindow:Math.max(0,Number(y)||0)}}function K(t={},{structured:s=!1,minQuality:l=0,hasTools:h=!1,background:d=!1}={}){return d?{prefer:"cost",why:"background work — spend as little as possible"}:s||t.complexity==="high"||t.code||t.modality==="vision"?{prefer:"quality",why:"the task is exact or hard — get it right rather than quick"}:t.smalltalk&&!h&&!l?{prefer:"latency",why:"nothing to look up — answer fast"}:{prefer:"balanced",why:"no reason to favour speed or quality"}}function O(t){return t?.orderPinned&&Number.isFinite(t.providerRank)?t.providerRank:1/0}const Q=.25,U=.25;function J(t=[],s={}){const l=i=>!!s.model&&S(i)===S(s);let h=[...t];if(s.reason==="gone"){const i=h.filter(n=>!l(n));i.length&&(h=i)}const d=i=>Number.isFinite(i.quality)?i.quality:.5,y=i=>(s.capabilities||[]).every(n=>(i.capabilities||[]).includes(n)),c=i=>!s.classUsed||i.classUsed===s.classUsed,a=Number.isFinite(s.quality)?s.quality:null;if(a!==null){const i=n=>l(n)?-1:Math.abs(d(n)-a)+(c(n)?0:Q)+(y(n)?0:U);return h.map(n=>({m:n,d:i(n)})).sort((n,p)=>n.d-p.d||O(n.m)-O(p.m)||n.m.costPer1k-p.m.costPer1k||String(n.m.id).localeCompare(String(p.m.id))).map(n=>n.m)}const r=i=>l(i)?0:c(i)&&y(i)?1:c(i)?2:y(i)?3:4;return h.sort((i,n)=>r(i)-r(n)||d(n)-d(i)||O(i)-O(n)||i.costPer1k-n.costPer1k)}function X(t,s={}){const l=String(t||""),h=String(s?.action||""),d=`${l}.${h}`;return/screenshot|marked_screenshot|read_canvas|sense_canvas/.test(d)?{required:["vision"],why:"this step reads an image"}:/structured_insert|sheet_write|fill_form|input_sequence|draw_path/.test(d)?{required:["tools"],minQuality:.55,why:"this step writes an exact payload"}:{required:l?["tools"]:[],why:""}}function Z({models:t=[],middleware:s=[],strategies:l=[],admit:h=null}={}){const d=[...t],y=[...s],c=[...l],a=r=>y.filter(i=>i.stage===r&&(!h||h(i))).sort((i,n)=>r==="request"?i.priority-n.priority:n.priority-i.priority);return{addModel(r){return d.push(r),()=>{const i=d.indexOf(r);i>=0&&d.splice(i,1)}},use(r){return y.push(r),()=>{const i=y.indexOf(r);i>=0&&y.splice(i,1)}},addStrategy(r){return c.push(r),()=>{const i=c.indexOf(r);i>=0&&c.splice(i,1)}},models:()=>[...d],middleware:()=>[...y],strategies:()=>[...c],route(r={}){const i=C.includes(r.reach)?r.reach:"any",n=r.capabilities||[],p=r.requirementReasons||[],u=[],g=d.filter(e=>{if(!e.available)return u.push({id:e.id,why:"unavailable"}),!1;if(h&&!h(e))return u.push({id:e.id,why:"disabled"}),!1;if(F(e.reach)>F(i))return u.push({id:e.id,why:`reach '${e.reach}' exceeds '${i}'`}),!1;const o=n.filter(k=>!e.capabilities.includes(k));if(o.length)return u.push({id:e.id,why:`missing ${o.join(", ")}`}),!1;if(r.minWindow>0&&Number(e.window)>0&&Number(e.window)<r.minWindow)return u.push({id:e.id,why:`a ${Math.round(e.window/1e3)}k window under the ${Math.round(r.minWindow/1e3)}k this turn needs`}),!1;if(r.maxLatencyMs>0&&e.latencyMs>r.maxLatencyMs)return u.push({id:e.id,why:`${e.latencyMs}ms exceeds the ${r.maxLatencyMs}ms deadline`}),!1;if(r.maxCostPer1k>=0&&r.maxCostPer1k!==void 0&&e.costPer1k>r.maxCostPer1k)return u.push({id:e.id,why:`costs ${e.costPer1k} over the ${r.maxCostPer1k} budget`}),!1;if(e.rateLimited)return u.push({id:e.id,why:"rate limited"}),!1;if(r.exclude?.includes?.(e.id))return u.push({id:e.id,why:"already failed this request"}),!1;if(r.minQuality>0){const k=Number.isFinite(e.quality)?e.quality:.5;if(k<r.minQuality)return u.push({id:e.id,why:`below the quality this task needs (${k} < ${r.minQuality})`}),!1}return!0});if(!g.length){if(r.minQuality>0){const e=this.route({...r,minQuality:0});if(e.model)return{...e,relaxed:!0,reasons:[...e.reasons,`no model met the quality this task needs (${r.minQuality}) — used the best available instead`]}}if(r.negotiable?.length){const e=(r.capabilities||[]).filter(k=>!r.negotiable.includes(k)),o=this.route({...r,minQuality:0,capabilities:e,negotiable:[]});if(o.model)return{...o,relaxed:!0,reasons:[...o.reasons,`no model offers ${r.negotiable.join(", ")} — used one without it, which may do this task poorly`]}}return{model:null,reasons:["no candidate satisfies the constraints"],constraints:p,rejected:u}}const b=r.prefer||"balanced",v=e=>{const o=1+Math.max(0,Math.min(1,e.load)),k=Number.isFinite(e.quality)?Math.max(.1,e.quality):.5,P=j[e.reach]??1;return b==="latency"?e.latencyMs*o*P:b==="cost"?e.costPer1k*o*P:b==="quality"?o/k:(e.latencyMs/1e3+e.costPer1k*L)*o*P/k},x=new Map,w=e=>(x.has(e)||x.set(e,v(e)),x.get(e)),$=(e,o)=>e.providerRank-o.providerRank||w(e)-w(o)||e.id.localeCompare(o.id),f=(e,o)=>w(e)-w(o)||e.providerRank-o.providerRank||e.id.localeCompare(o.id),m=new Map;for(const e of g){const o=S(e)||`#${e.id}`;m.has(o)||m.set(o,[]),m.get(o).push(e)}const _=[...m.values()].map(e=>[...e].sort(e.some(o=>o.orderPinned)?$:f));_.sort((e,o)=>w(e[0])-w(o[0])||$(e[0],o[0]));const R=[];for(const e of _){const o=R[R.length-1],k=o?w(o[0][0]):0;o&&w(e[0])<=k*(1+T)?o.push(e):R.push([e])}for(const e of R)e.sort((o,k)=>$(o[0],k[0]));let M=R.flat(2);const A=b==="balanced"?M.filter(e=>e.orderPinned).sort((e,o)=>e.providerRank-o.providerRank)[0]:null;A&&(M=[A,...M.filter(e=>e!==A)]);const N=R[0]?.length>1,I=(R[0]||[]).flat().length,E=M[0];return{model:E,eligible:M,constraints:p,strategy:A?"declared-default":"default-score",reasons:[`reach '${E.reach}' within '${i}'`,n.length?`has ${n.join(", ")}`:"no special capability needed",A?`your default (Order ${E.providerRank}) — nothing about this turn asked for anything else`:N?`order ${E.providerRank} broke a ${I}-way tie by ${b}, of ${M.length} eligible`:`best by ${b} (${M.length} eligible)`],rejected:u,runnersUp:M.slice(1).map(e=>e.id)}},async routeWith(r={},i={}){const n=this.route(r);if(!n.model||!c.length)return n;const p=new Map(n.eligible.map(u=>[u.id,u]));for(const u of c){if(h&&!h(u))continue;let g=null;try{const m=u.decide([...n.eligible],r,i);g=u.timeoutMs>0?await Promise.race([m,new Promise(_=>setTimeout(()=>_(null),u.timeoutMs))]):await m}catch{g=null}if(!g)continue;const b=Array.isArray(g)?g:Array.isArray(g?.ranked)?g.ranked:[g],v=Array.isArray(g?.why)?g.why.filter(m=>typeof m=="string"&&m):[],x=b.map(m=>typeof m=="string"?p.get(m):p.get(m?.id)).filter(Boolean),w=b.length-x.length;if(!x.length)continue;const $=n.eligible.filter(m=>!x.includes(m)),f=[...x,...$];return{...n,model:x[0],eligible:f,strategy:u.id,runnersUp:f.slice(1).map(m=>m.id),reasons:[...n.reasons.slice(0,-1),`chosen by '${u.id}' (class ${u.classUsed}) from ${n.eligible.length} eligible`,...v,...w>0?[`${w} suggestion(s) ignored — not eligible under the constraints`]:[]]}}return n},async run(r,{dispatch:i,need:n={}}={}){if(typeof i!="function")throw new q("NO_DISPATCH","run needs a dispatch function");const p=await this.routeWith(n,{request:r});if(!p.model)throw new q("NO_ROUTE",p.reasons[0]);const u=f=>!f.requiredFor||f.requiredFor(p.model,n),g=y.filter(f=>f.requiredFor&&f.requiredFor(p.model,n)),b=new Set(a("request").concat(a("response")).map(f=>f.id)),v=g.filter(f=>!b.has(f.id));if(v.length)throw new q("MISSING_REQUIRED",`route to '${p.model.id}' requires ${v.map(f=>f.id).join(", ")}, which is not active`);const x={model:p.model,need:n,decision:p};let w=r;for(const f of a("request"))u(f)&&(w=await f.run(w,x)??w);let $=await i(w,x);for(const f of a("response"))u(f)&&($=await f.run($,x)??$);return{answer:$,decision:p}}}}export{U as FAILOVER_CAPABILITY_GAP,Q as FAILOVER_CLASS_GAP,re as REACH,q as RouterError,Z as createModelRouter,G as defineMiddleware,W as defineModel,H as defineRouteStrategy,J as failoverOrder,O as pinnedOrderOf,K as preferenceFor,ie as reachRank,V as requirementsFor,X as requirementsForStep,S as sameModelKey,Y as signalsFrom};
package/sandbox-policy.js CHANGED
@@ -1 +1 @@
1
- import{EventError as A}from"./event.js";import{normalizeGrant as b}from"./sandbox-grant.js";const y=Object.freeze(["none","process","container","kubernetes"]),E=Object.freeze(["open","allowlist","none","gateway"]),_=Object.freeze(["~/.chatpanel","~/.ssh","~/.gnupg","~/.aws","~/.azure","~/.config/gcloud","~/.kube","~/.netrc","~/.docker/config.json","~/.npmrc","~/.pypirc"]),x=Object.freeze(["/tmp","/private/tmp","~/.cache","~/.npm","~/.local/share/uv","~/.local/state"]),h=Object.freeze({codex:Object.freeze({hosts:["api.openai.com","chatgpt.com","auth.openai.com","*.openai.com"],write:["~/.codex"]}),claude:Object.freeze({hosts:["api.anthropic.com","*.anthropic.com","claude.ai","statsig.anthropic.com"],write:["~/.claude","~/.claude.json"]}),antigravity:Object.freeze({hosts:["*.googleapis.com","*.google.com","oauth2.googleapis.com"],write:["~/.gemini","~/.antigravity","~/.config/antigravity"]}),custom:Object.freeze({hosts:[],write:[]}),mcp:Object.freeze({hosts:[],write:[]}),extract:Object.freeze({hosts:[],write:[]})}),R=Object.freeze(["github.com","*.github.com","*.githubusercontent.com","gitlab.com","bitbucket.org","registry.npmjs.org","pypi.org","files.pythonhosted.org","crates.io","static.crates.io","proxy.golang.org","sum.golang.org","huggingface.co","*.huggingface.co"]),u=e=>!!e&&typeof e=="object"&&!Array.isArray(e),g=e=>Array.isArray(e)&&e.every(o=>typeof o=="string"&&o.length>0),c=(e,o)=>{if(!e)throw new A("SHAPE",o)},f=e=>[...new Set(e)];function O(e){c(u(e),"kit: must be an object"),c(typeof e.id=="string"&&e.id.length>0,"kit: id required"),c(u(e.network)&&E.includes(e.network.mode),`kit ${e.id}: network.mode must be one of ${E.join(", ")}`),c(g(e.network.allowedDomains||[]),`kit ${e.id}: network.allowedDomains must be string[]`),c(g(e.network.deniedDomains||[]),`kit ${e.id}: network.deniedDomains must be string[]`),c(u(e.filesystem),`kit ${e.id}: filesystem required`);for(const o of["allowWrite","denyWrite","allowRead","denyRead"])c(g(e.filesystem[o]||[]),`kit ${e.id}: filesystem.${o} must be string[]`);return c(g(e.filesystem.allowWrite)&&e.filesystem.allowWrite.length>0,`kit ${e.id}: filesystem.allowWrite must name at least the working directory`),e.image!=null&&c(typeof e.image=="string",`kit ${e.id}: image must be a string`),e.credentials!=null&&c(Array.isArray(e.credentials)&&e.credentials.every(o=>u(o)&&typeof o.name=="string"&&typeof o.forHost=="string"),`kit ${e.id}: credentials must be [{ name, forHost }]`),{id:e.id,kind:e.kind||"process",image:e.image||null,network:{mode:e.network.mode,allowedDomains:f(e.network.allowedDomains||[]),deniedDomains:f(e.network.deniedDomains||[])},filesystem:{allowWrite:f(e.filesystem.allowWrite),denyWrite:f(e.filesystem.denyWrite||[]),allowRead:f(e.filesystem.allowRead||[]),denyRead:f(e.filesystem.denyRead||[])},credentials:e.credentials||[],limits:u(e.limits)?{...e.limits}:{}}}import{normalizeGrant as M,mergeGrants as k,parseHostList as q}from"./sandbox-grant.js";function N({engine:e="custom",cwd:o,mode:t="open",extraHosts:r=[],extraWrite:n=[],extraDenyRead:s=[],grant:l=null}={}){const d=h[e]||h.custom;c(typeof o=="string"&&o.length>0,"kit: cwd required");const a=b(l);return O({id:`${e}:${t}`,kind:"process",network:{mode:t,allowedDomains:t==="open"?["*"]:t==="none"?[]:f([...d.hosts,...R,...r,...a.hosts]),deniedDomains:[]},filesystem:{allowWrite:f([o,...x,...d.write,...n,...a.write.filter(i=>!_.some(p=>i===p||i.startsWith(`${p}/`)))]),denyWrite:[],allowRead:[o],denyRead:f([..._,...s])}})}function z(e,{loopback:o=[],home:t="",platform:r="darwin"}={}){const n=O(e),s=d=>t&&d.startsWith("~")?t+d.slice(1):d,l=n.network.mode==="none"?[]:o.map(d=>`127.0.0.1:${d}`);return{network:{allowedDomains:f([...n.network.allowedDomains,...l]),deniedDomains:n.network.deniedDomains,allowLocalBinding:r==="darwin"&&l.length>0},filesystem:{denyRead:n.filesystem.denyRead.map(s),allowRead:n.filesystem.allowRead.map(s),allowWrite:n.filesystem.allowWrite.map(s),denyWrite:n.filesystem.denyWrite.map(s)}}}function C({layer:e="none",runtime:o=null,kitId:t=null,mode:r=null,reason:n=null,hosts:s=null}={}){return c(y.includes(e),`sandbox record: layer must be one of ${y.join(", ")}`),{layer:e,runtime:o,kit:t,mode:r,...e==="none"&&n?{reason:n}:{},...Array.isArray(s)&&s.length?{hosts:f(s)}:{}}}function S(e,{platform:o="darwin"}={}){const t=String(e);if(o==="win32"){c(!/[\r\n]/.test(t),"win32 command line: an argument holds a newline, which cmd.exe cannot carry");let r=t;if(t===""||/[ \t\v"]/.test(t)){r='"';for(let n=0;n<t.length;n++){let s=0;for(;n<t.length&&t[n]==="\\";)s++,n++;if(n===t.length){r+="\\".repeat(s*2);break}t[n]==='"'?r+="\\".repeat(s*2+1)+'"':r+="\\".repeat(s)+t[n]}r+='"'}return r.replace(/[()%!^"<>&|]/g,"^$&")}return t===""?"''":/^[A-Za-z0-9_\-./=:@%+,]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`}const I=Object.freeze(["SSL_CERT_FILE","REQUESTS_CA_BUNDLE","CURL_CA_BUNDLE","GIT_SSL_CAINFO"]);function H(e={},{platform:o="darwin",caBundle:t=""}={}){const r={NODE_USE_ENV_PROXY:"1"};if(t)for(const n of I)e[n]||(r[n]=t);if(o==="linux")for(const n of["no_proxy","NO_PROXY"])typeof e[n]=="string"&&(r[n]=e[n].split(",").map(s=>s.trim()).filter(s=>s&&!/^(localhost|127\.0\.0\.1|::1|\[::1\])$/i.test(s)).join(","));return r}function L(e,o=[],{platform:t="darwin"}={}){return[e,...o].map(r=>S(r,{platform:t})).join(" ")}const T=/[\\/]+/,m=e=>String(e||"").replace(/\//g,"\\").replace(/\\+$/,"").toLowerCase(),D=e=>/^[a-z]:$/i.test(m(e))||m(e)==="";function w(e,o){const t=m(e),r=m(o);return!!r&&t!==r&&t.startsWith(r+"\\")}function W(e){const o=String(e||"").replace(/\//g,"\\").split("\\");if(o.length<2)return"";const t=o.findIndex(r=>r.toLowerCase()==="node_modules");return(t>0?o.slice(0,t):o.slice(0,-1)).join("\\")}function K({kit:e,files:o=[],home:t}){c(typeof t=="string"&&t.length>0,"windows grants: home required");const r=a=>(a.startsWith("~")?t+a.slice(1):a).replace(/\//g,"\\"),n=[];for(const a of e?.filesystem?.allowWrite||[]){const i=r(a);!/^[a-z]:\\/i.test(i)&&!i.startsWith("\\\\")||(c(!D(i)&&m(i)!==m(t),`windows grants: a write on ${i} would hand the sandbox account the whole profile`),w(i,t)&&n.push(i))}const s=(a,i)=>i.some(p=>m(a)===m(p)||w(a,p)),l=[];for(const a of o){const i=W(a);i&&w(i,t)&&l.push(i)}for(const a of e?.filesystem?.allowRead||[]){const i=r(a);w(i,t)&&l.push(i)}const d=f(l).filter(a=>!s(a,n));return{read:d.filter(a=>!d.some(i=>i!==a&&w(a,i))),write:f(n)}}const j=Object.freeze(["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_BASE_URL","CLAUDE_CONFIG_DIR","OPENAI_API_KEY","OPENAI_BASE_URL","OPENAI_API_BASE","CODEX_HOME","GEMINI_API_KEY","GOOGLE_API_KEY","DEEPSEEK_API_KEY","DSH_HOME","OPENROUTER_API_KEY","GROQ_API_KEY","XAI_API_KEY","MISTRAL_API_KEY"]);function Y({engine:e="custom",home:o,env:t={},base:r={},carry:n=j}={}){c(typeof o=="string"&&o.length>0,"windows env: home required");const s=o.replace(/\//g,"\\"),l=/^[a-z]:/i.test(s)?s.slice(0,2):"",d={USERPROFILE:s,...l?{HOMEDRIVE:l,HOMEPATH:s.slice(2)}:{}};for(const[a,i]of Object.entries(t))typeof i=="string"&&(r[a]!==i||n.includes(a))&&(d[a]=i);return e==="codex"&&!d.CODEX_HOME&&(d.CODEX_HOME=s+"\\.codex"),d}function v(e,o){c(Array.isArray(e),"srt-win argv: must be an array");const t=e.indexOf("exec"),r=t>=0?e.indexOf("--",t+1):-1;c(t>=0&&r>t,"srt-win argv: expected `exec … -- <shell> <command>`");const n=new Set;for(let l=t+1;l<r;l++)e[l]==="--env"&&typeof e[l+1]=="string"&&n.add(e[l+1].split("=")[0].toUpperCase());const s=[];for(const[l,d]of Object.entries(o||{}))c(/^[A-Za-z_][A-Za-z0-9_]*$/.test(l),`srt-win env: bad key ${l}`),c(!/[\r\n]/.test(d),`srt-win env: ${l} holds a newline`),n.has(l.toUpperCase())||s.push("--env",`${l}=${d}`);return[...e.slice(0,r),...s,...e.slice(r)]}export{x as COMMON_WRITE,R as DEVELOPER_HOSTS,h as ENGINE_KITS,E as NETWORK_MODES,y as SANDBOX_LAYERS,_ as SECRET_PATHS,j as WINDOWS_CARRY_KEYS,N as kitFor,k as mergeGrants,M as normalizeGrant,q as parseHostList,H as sandboxEnvOverlay,C as sandboxRecord,L as shellJoin,S as shellQuote,z as toSrtSettings,w as underWindowsHome,O as validateKit,K as windowsGrantsFor,W as windowsInstallRoot,Y as windowsSandboxEnv,v as withSrtWinEnv};
1
+ import{EventError as b}from"./event.js";import{normalizeGrant as A}from"./sandbox-grant.js";const y=Object.freeze(["none","process","container","kubernetes"]),E=Object.freeze(["open","allowlist","none","gateway"]),h=Object.freeze(["~/.chatpanel","~/.ssh","~/.gnupg","~/.aws","~/.azure","~/.config/gcloud","~/.kube","~/.netrc","~/.docker/config.json","~/.npmrc","~/.pypirc"]),x=Object.freeze(["/tmp","/private/tmp","~/.cache","~/.npm","~/.local/share/uv","~/.local/state"]),_=Object.freeze({codex:Object.freeze({hosts:["api.openai.com","chatgpt.com","auth.openai.com","*.openai.com"],write:["~/.codex"]}),claude:Object.freeze({hosts:["api.anthropic.com","*.anthropic.com","claude.ai","statsig.anthropic.com"],write:["~/.claude","~/.claude.json"]}),antigravity:Object.freeze({hosts:["*.googleapis.com","*.google.com","oauth2.googleapis.com"],write:["~/.gemini","~/.antigravity","~/.config/antigravity"]}),custom:Object.freeze({hosts:[],write:[]}),mcp:Object.freeze({hosts:[],write:[]}),extract:Object.freeze({hosts:[],write:[]}),"model-server":Object.freeze({hosts:["huggingface.co","*.huggingface.co","*.hf.co","cdn-lfs.huggingface.co","cas-bridge.xethub.hf.co","dl.chatpanel.net"],write:[]})}),R=Object.freeze(["github.com","*.github.com","*.githubusercontent.com","gitlab.com","bitbucket.org","registry.npmjs.org","pypi.org","files.pythonhosted.org","crates.io","static.crates.io","proxy.golang.org","sum.golang.org","huggingface.co","*.huggingface.co"]),p=e=>!!e&&typeof e=="object"&&!Array.isArray(e),g=e=>Array.isArray(e)&&e.every(o=>typeof o=="string"&&o.length>0),l=(e,o)=>{if(!e)throw new b("SHAPE",o)},f=e=>[...new Set(e)];function O(e){l(p(e),"kit: must be an object"),l(typeof e.id=="string"&&e.id.length>0,"kit: id required"),l(p(e.network)&&E.includes(e.network.mode),`kit ${e.id}: network.mode must be one of ${E.join(", ")}`),l(g(e.network.allowedDomains||[]),`kit ${e.id}: network.allowedDomains must be string[]`),l(g(e.network.deniedDomains||[]),`kit ${e.id}: network.deniedDomains must be string[]`),l(p(e.filesystem),`kit ${e.id}: filesystem required`);for(const o of["allowWrite","denyWrite","allowRead","denyRead"])l(g(e.filesystem[o]||[]),`kit ${e.id}: filesystem.${o} must be string[]`);return l(g(e.filesystem.allowWrite)&&e.filesystem.allowWrite.length>0,`kit ${e.id}: filesystem.allowWrite must name at least the working directory`),e.image!=null&&l(typeof e.image=="string",`kit ${e.id}: image must be a string`),e.credentials!=null&&l(Array.isArray(e.credentials)&&e.credentials.every(o=>p(o)&&typeof o.name=="string"&&typeof o.forHost=="string"),`kit ${e.id}: credentials must be [{ name, forHost }]`),{id:e.id,kind:e.kind||"process",image:e.image||null,network:{mode:e.network.mode,allowedDomains:f(e.network.allowedDomains||[]),deniedDomains:f(e.network.deniedDomains||[])},filesystem:{allowWrite:f(e.filesystem.allowWrite),denyWrite:f(e.filesystem.denyWrite||[]),allowRead:f(e.filesystem.allowRead||[]),denyRead:f(e.filesystem.denyRead||[])},credentials:e.credentials||[],limits:p(e.limits)?{...e.limits}:{}}}import{normalizeGrant as M,mergeGrants as k,parseHostList as q}from"./sandbox-grant.js";function z({engine:e="custom",cwd:o,mode:t="open",extraHosts:r=[],extraWrite:n=[],extraDenyRead:s=[],grant:c=null}={}){const d=_[e]||_.custom;l(typeof o=="string"&&o.length>0,"kit: cwd required");const a=A(c);return O({id:`${e}:${t}`,kind:"process",network:{mode:t,allowedDomains:t==="open"?["*"]:t==="none"?[]:f([...d.hosts,...R,...r,...a.hosts]),deniedDomains:[]},filesystem:{allowWrite:f([o,...x,...d.write,...n,...a.write.filter(i=>!h.some(u=>i===u||i.startsWith(`${u}/`)))]),denyWrite:[],allowRead:[o],denyRead:f([...h,...s])}})}function N(e,{loopback:o=[],home:t="",platform:r="darwin"}={}){const n=O(e),s=d=>t&&d.startsWith("~")?t+d.slice(1):d,c=n.network.mode==="none"?[]:o.map(d=>`127.0.0.1:${d}`);return{network:{allowedDomains:f([...n.network.allowedDomains,...c]),deniedDomains:n.network.deniedDomains,allowLocalBinding:r==="darwin"&&c.length>0},filesystem:{denyRead:n.filesystem.denyRead.map(s),allowRead:n.filesystem.allowRead.map(s),allowWrite:n.filesystem.allowWrite.map(s),denyWrite:n.filesystem.denyWrite.map(s)}}}function C({layer:e="none",runtime:o=null,kitId:t=null,mode:r=null,reason:n=null,hosts:s=null}={}){return l(y.includes(e),`sandbox record: layer must be one of ${y.join(", ")}`),{layer:e,runtime:o,kit:t,mode:r,...e==="none"&&n?{reason:n}:{},...Array.isArray(s)&&s.length?{hosts:f(s)}:{}}}function S(e,{platform:o="darwin"}={}){const t=String(e);if(o==="win32"){l(!/[\r\n]/.test(t),"win32 command line: an argument holds a newline, which cmd.exe cannot carry");let r=t;if(t===""||/[ \t\v"]/.test(t)){r='"';for(let n=0;n<t.length;n++){let s=0;for(;n<t.length&&t[n]==="\\";)s++,n++;if(n===t.length){r+="\\".repeat(s*2);break}t[n]==='"'?r+="\\".repeat(s*2+1)+'"':r+="\\".repeat(s)+t[n]}r+='"'}return r.replace(/[()%!^"<>&|]/g,"^$&")}return t===""?"''":/^[A-Za-z0-9_\-./=:@%+,]+$/.test(t)?t:`'${t.replace(/'/g,"'\\''")}'`}const I=Object.freeze(["SSL_CERT_FILE","REQUESTS_CA_BUNDLE","CURL_CA_BUNDLE","GIT_SSL_CAINFO"]);function H(e={},{platform:o="darwin",caBundle:t=""}={}){const r={NODE_USE_ENV_PROXY:"1"};if(t)for(const n of I)e[n]||(r[n]=t);if(o==="linux")for(const n of["no_proxy","NO_PROXY"])typeof e[n]=="string"&&(r[n]=e[n].split(",").map(s=>s.trim()).filter(s=>s&&!/^(localhost|127\.0\.0\.1|::1|\[::1\])$/i.test(s)).join(","));return r}function L(e,o=[],{platform:t="darwin"}={}){return[e,...o].map(r=>S(r,{platform:t})).join(" ")}const T=/[\\/]+/,m=e=>String(e||"").replace(/\//g,"\\").replace(/\\+$/,"").toLowerCase(),D=e=>/^[a-z]:$/i.test(m(e))||m(e)==="";function w(e,o){const t=m(e),r=m(o);return!!r&&t!==r&&t.startsWith(r+"\\")}function j(e){const o=String(e||"").replace(/\//g,"\\").split("\\");if(o.length<2)return"";const t=o.findIndex(r=>r.toLowerCase()==="node_modules");return(t>0?o.slice(0,t):o.slice(0,-1)).join("\\")}function K({kit:e,files:o=[],home:t}){l(typeof t=="string"&&t.length>0,"windows grants: home required");const r=a=>(a.startsWith("~")?t+a.slice(1):a).replace(/\//g,"\\"),n=[];for(const a of e?.filesystem?.allowWrite||[]){const i=r(a);!/^[a-z]:\\/i.test(i)&&!i.startsWith("\\\\")||(l(!D(i)&&m(i)!==m(t),`windows grants: a write on ${i} would hand the sandbox account the whole profile`),w(i,t)&&n.push(i))}const s=(a,i)=>i.some(u=>m(a)===m(u)||w(a,u)),c=[];for(const a of o){const i=j(a);i&&w(i,t)&&c.push(i)}for(const a of e?.filesystem?.allowRead||[]){const i=r(a);w(i,t)&&c.push(i)}const d=f(c).filter(a=>!s(a,n));return{read:d.filter(a=>!d.some(i=>i!==a&&w(a,i))),write:f(n)}}const W=Object.freeze(["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_BASE_URL","CLAUDE_CONFIG_DIR","OPENAI_API_KEY","OPENAI_BASE_URL","OPENAI_API_BASE","CODEX_HOME","GEMINI_API_KEY","GOOGLE_API_KEY","DEEPSEEK_API_KEY","DSH_HOME","OPENROUTER_API_KEY","GROQ_API_KEY","XAI_API_KEY","MISTRAL_API_KEY"]);function v({engine:e="custom",home:o,env:t={},base:r={},carry:n=W}={}){l(typeof o=="string"&&o.length>0,"windows env: home required");const s=o.replace(/\//g,"\\"),c=/^[a-z]:/i.test(s)?s.slice(0,2):"",d={USERPROFILE:s,...c?{HOMEDRIVE:c,HOMEPATH:s.slice(2)}:{}};for(const[a,i]of Object.entries(t))typeof i=="string"&&(r[a]!==i||n.includes(a))&&(d[a]=i);return e==="codex"&&!d.CODEX_HOME&&(d.CODEX_HOME=s+"\\.codex"),d}function Y(e,o){l(Array.isArray(e),"srt-win argv: must be an array");const t=e.indexOf("exec"),r=t>=0?e.indexOf("--",t+1):-1;l(t>=0&&r>t,"srt-win argv: expected `exec … -- <shell> <command>`");const n=new Set;for(let c=t+1;c<r;c++)e[c]==="--env"&&typeof e[c+1]=="string"&&n.add(e[c+1].split("=")[0].toUpperCase());const s=[];for(const[c,d]of Object.entries(o||{}))l(/^[A-Za-z_][A-Za-z0-9_]*$/.test(c),`srt-win env: bad key ${c}`),l(!/[\r\n]/.test(d),`srt-win env: ${c} holds a newline`),n.has(c.toUpperCase())||s.push("--env",`${c}=${d}`);return[...e.slice(0,r),...s,...e.slice(r)]}export{x as COMMON_WRITE,R as DEVELOPER_HOSTS,_ as ENGINE_KITS,E as NETWORK_MODES,y as SANDBOX_LAYERS,h as SECRET_PATHS,W as WINDOWS_CARRY_KEYS,z as kitFor,k as mergeGrants,M as normalizeGrant,q as parseHostList,H as sandboxEnvOverlay,C as sandboxRecord,L as shellJoin,S as shellQuote,N as toSrtSettings,w as underWindowsHome,O as validateKit,K as windowsGrantsFor,j as windowsInstallRoot,v as windowsSandboxEnv,Y as withSrtWinEnv};
package/schedule.js CHANGED
@@ -1 +1 @@
1
- class a extends Error{constructor(t,n){super(n),this.name="ScheduleError",this.code=t}}const T=Object.freeze(["once","interval","daily","weekly"]),j=Object.freeze(["timer","meeting","voice","data","channel"]),S=Object.freeze(["skill","prompt","monitor","notify"]),O=Object.freeze(["skip","runOnce","runAll"]),$=20;function g(e,{days:t=0,hour:n,minute:r=0}){const o=new Date(e);return o.setDate(o.getDate()+t),o.setHours(n,r,0,0),o.getTime()}const I=e=>{const t=new Date(e).getDay();return t===0||t===6};function E(e){if(!e||typeof e!="object")throw new a("BAD_SCHEDULE","schedule must be an object");if(!T.includes(e.kind))throw new a("BAD_SCHEDULE",`unknown schedule kind '${e.kind}'`);if(e.kind==="once"&&!(e.at>0))throw new a("BAD_SCHEDULE","once needs `at`");if(e.kind==="interval"&&!(e.everyMs>=6e4))throw new a("BAD_SCHEDULE","interval needs everyMs >= 60000");if(e.kind==="daily"||e.kind==="weekly"){if(!Number.isInteger(e.hour)||e.hour<0||e.hour>23)throw new a("BAD_SCHEDULE","hour must be 0-23");const t=e.minute??0;if(!Number.isInteger(t)||t<0||t>59)throw new a("BAD_SCHEDULE","minute must be 0-59")}if(e.kind==="weekly"&&(!Number.isInteger(e.weekday)||e.weekday<0||e.weekday>6))throw new a("BAD_SCHEDULE","weekly needs weekday 0-6 (Sunday = 0)");return e}function A(e,t){const n=E(e),r=n.minute??0;switch(n.kind){case"once":return n.at>t?n.at:null;case"interval":{const o=n.anchor??t;if(o>t)return o;const i=Math.floor((t-o)/n.everyMs)+1;return o+i*n.everyMs}case"daily":{let o=g(t,{hour:n.hour,minute:r});if(o<=t&&(o=g(t,{days:1,hour:n.hour,minute:r})),n.weekdaysOnly)for(let i=0;i<7&&I(o);i++)o=g(o,{days:1,hour:n.hour,minute:r});return o}case"weekly":{const o=new Date(t).getDay();let i=(n.weekday-o+7)%7;return i===0&&g(t,{hour:n.hour,minute:r})<=t&&(i=7),g(t,{days:i,hour:n.hour,minute:r})}default:return null}}const B=Object.freeze(["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]),w=e=>`${String(e?.hour??0).padStart(2,"0")}:${String(e?.minute??0).padStart(2,"0")}`;function Y(e){if(!e||typeof e!="object")return"";switch(e.kind){case"once":return e.at>0?`once, at ${new Date(e.at).toLocaleString()}`:"";case"interval":{const t=Number(e.everyMs)||0;if(t<6e4)return"";const n=Math.round(t/6e4);if(n%1440===0){const r=n/1440;return`every ${r===1?"day":`${r} days`}`}if(n%60===0){const r=n/60;return`every ${r===1?"hour":`${r} hours`}`}return`every ${n} minutes`}case"daily":return e.weekdaysOnly?`every weekday at ${w(e)}`:`every day at ${w(e)}`;case"weekly":{const t=B[e.weekday];return t?`every ${t} at ${w(e)}`:""}default:return""}}function L(e,t,n,r=$){const o=[];let i=t;for(;o.length<r;){const s=A(e,i);if(s===null||s>n)break;o.push(s),i=s}return o}function d({id:e,label:t,kind:n,watches:r=[],description:o="",classUsed:i="R",matches:s=null,params:u={}}){if(!e)throw new a("BAD_TRIGGER","trigger.id required");if(!j.includes(n))throw new a("BAD_TRIGGER",`trigger '${e}': unknown kind '${n}'`);if(n!=="timer"&&typeof s!="function")throw new a("BAD_TRIGGER",`trigger '${e}': an event trigger needs matches()`);return Object.freeze({id:e,label:t||e,kind:n,watches:Object.freeze([...r]),description:o,classUsed:i,matches:s,params:Object.freeze({...u})})}function V(e=[]){const t=[...e];return{add(n){return t.push(n),()=>{const r=t.indexOf(n);r>=0&&t.splice(r,1)}},list:()=>[...t],get:n=>t.find(r=>r.id===n)||null}}const C=e=>String(e||"").toLowerCase().match(/[\p{L}\p{N}']+/gu)||[],h=e=>String(e||"").trim().toLowerCase(),D=3,M=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");function p(e,t=120){const n=String(e||"").replace(/\s+/g," ").trim();if(n.length<=t)return n;const r=n.slice(0,t),o=r.lastIndexOf(" ");return`${(o>t*.6?r.slice(0,o):r).replace(/[\s,;:.!?—-]+$/,"")}…`}function R(e,t){const n=h(t);if(n.length<D)return!1;const r=/[\p{L}\p{N}]/u.test(n[0])?"\\b":"",o=/[\p{L}\p{N}]/u.test(n[n.length-1])?"\\b":"";try{return new RegExp(`${r}${M(n)}${o}`,"iu").test(String(e||""))}catch{return h(e).includes(n)}}function y(e,t,n){return e==="me"?!!n?.isSelf?.(t):e==="others"?!n?.isSelf?.(t):!0}const N=Object.freeze(new Set(["and","or","but","so","because","cause","cos","since","although","though","while","whereas","unless","until","if","when","whenever","that","which","who","whom","whose","than","as","like","what","to","of","in","on","at","by","for","from","with","without","about","into","onto","over","under","between","through","during","against","per","a","an","the","my","our","your","their","its","is","are","was","were","be","been","being","am","do","does","did","have","has","had","will","would","can","could","should","shall","may","might","must","um","uh","er"]));function Z(e){const t=String(e||"").trim();if(!t)return!1;if(/[.!?…]["'\u2019\u201d)\]]*$/.test(t))return!0;if(/[,;:\-\u2013\u2014]$/.test(t))return!1;const n=t.toLowerCase().match(/[\p{L}\p{N}']+/gu)||[],r=n[n.length-1];return r?!N.has(r):!0}const v="text.delta",_=Object.freeze(["meeting","note","chat"]),k=Object.freeze(["meeting.transcript.delta",v]);function G(e){if(e?.type==="meeting.transcript.delta")return"meeting";const t=h(e?.source);return _.includes(t)?t:""}function b(e,t){const n=G(t);if(!n)return!1;const r=(Array.isArray(e)?e:[]).map(h).filter(o=>_.includes(o));return r.length?r.includes(n):n==="meeting"}const m=d({id:"timer:schedule",label:"On a schedule",kind:"timer",description:'Once, on an interval, daily, or on a weekday — "every weekday at 8am".'}),W=d({id:"meeting:started",label:"When a meeting starts",kind:"meeting",watches:["meeting.started"],matches:(e,t={})=>t.platform&&h(e.platform)!==h(t.platform)||t.titleIncludes&&!h(e.title).includes(h(t.titleIncludes))?null:{why:`meeting started: ${e.title||e.meetingId}`}}),H=d({id:"meeting:ended",label:"When a meeting ends",kind:"meeting",watches:["meeting.ended"],matches:e=>({why:`meeting ended: ${e.title||e.meetingId}`})}),U=d({id:"meeting:person-joined",label:"When someone joins",kind:"meeting",watches:["meeting.person-joined"],matches:(e,t={})=>{const n=(t.names||[]).map(h).filter(Boolean),r=(e.people||[]).filter(o=>!n.length||n.some(i=>h(o)===i||h(o).startsWith(`${i} `)));return r.length?{why:`joined: ${r.join(", ")}`,people:r}:null}}),z=d({id:"meeting:phrase",label:"When a phrase is said",kind:"meeting",watches:k,matches:(e,t={},n={})=>{if(!b(t.sources,e))return null;const r=(t.any||[]).map(h).filter(o=>o.length>=D);if(!r.length)return null;for(const o of e.segments||[]){if(!y(t.speaker,o.speaker,n))continue;const i=r.find(s=>R(o.text,s));if(i)return{why:`“${i}” said by ${o.speaker||"someone"}`,segment:o,phrase:i}}return null}}),J=d({id:"meeting:topic",label:"When someone talks about something",kind:"meeting",watches:k,matches:(e,t={},n={})=>{if(!b(t.sources,e))return null;const r=(t.terms||[]).map(h).filter(Boolean);if(!r.length)return null;const o=Math.max(1,Math.min(t.minHits||1,r.length)),i=(e.segments||[]).filter(c=>y(t.speaker,c.speaker,n)),s=new Set(i.flatMap(c=>C(c.text))),u=r.filter(c=>c.split(/\s+/).every(l=>s.has(l)));return u.length>=o?{why:`talking about ${u.join(", ")}`,terms:u}:null}}),q=/^(who|what|when|where|why|how|which|whose|can|could|would|should|shall|do|does|did|is|are|was|were|will|have|has|any(one|body)|is there|are there)\b/i,F=d({id:"meeting:question",label:"When a question is asked",kind:"meeting",watches:k,matches:(e,t={},n={})=>{if(!b(t.sources,e))return null;for(const r of e.segments||[]){if(!y(t.speaker||"anyone",r.speaker,n))continue;const o=String(r.text||"").trim();if(!(o.length<8)&&(o.includes("?")||q.test(o)))return{why:`question from ${r.speaker||"someone"}: “${p(o,100)}”`,segment:r}}return null}}),X=d({id:"voice:command",label:"When you say the wake word",kind:"voice",watches:["voice.command"],matches:(e,t={})=>{const n=t.intents||[];return!e.command?.allowed||n.length&&!n.includes(e.command.intent)?null:{why:`you said “${e.command.command}”`,command:e.command}}}),ee=Object.freeze([m,W,H,U,z,J,F,X]);function te({id:e,name:t,trigger:n,schedule:r=null,params:o={},action:i,enabled:s=!0,onMissed:u="runOnce",limits:c={},approval:l=null,createdAt:f=0}){if(!e)throw new a("BAD_JOB","job.id required");if(!t)throw new a("BAD_JOB",`job '${e}': name required`);if(!n)throw new a("BAD_JOB",`job '${e}': trigger required`);if(!i||!S.includes(i.kind))throw new a("BAD_JOB",`job '${e}': action.kind must be one of ${S}`);if(i.kind==="skill"&&!i.skillId)throw new a("BAD_JOB",`job '${e}': skill action needs skillId`);if(!O.includes(u))throw new a("BAD_JOB",`job '${e}': unknown onMissed '${u}'`);return(n===m.id||r)&&E(r),{id:e,name:t,trigger:n,schedule:r,params:{...o},action:{...i},enabled:!!s,onMissed:u,limits:{...c},approval:l,createdAt:f||0}}function x(e,t){return`${e}@${t}`}function ne(e,{now:t,lastRun:n={},admit:r=null,max:o=$}={}){const i=[];for(const s of e||[]){if(!s.enabled||s.trigger!==m.id||!s.schedule||r&&!r(s))continue;const u=n[s.id]||s.createdAt||0;if(!u)continue;const c=L(s.schedule,u,t,o);if(!c.length)continue;const l=s.onMissed==="runAll"?c:s.onMissed==="runOnce"?[c[c.length-1]]:[];for(const f of l)i.push({job:s,at:f,key:x(s.id,f),late:t-f>6e4,missedCount:c.length});l.length||i.push({job:s,at:c[c.length-1],key:x(s.id,c[c.length-1]),skipped:!0,missedCount:c.length})}return i}function re(e,{now:t,lastRun:n={}}={}){let r=null;for(const o of e||[]){if(!o.enabled||o.trigger!==m.id||!o.schedule)continue;const i=A(o.schedule,Math.max(t,n[o.id]||0));i!==null&&(r===null||i<r)&&(r=i)}return r}const K=8;function P(e=[],{max:t=K}={}){const n=[];for(const r of e){const o=String(r?.segment?.text||r?.why||"").trim();if(!o)continue;const i=h(r?.segment?.speaker),s=r?.segment?.t||0,u=o.toLowerCase().replace(/\s+/g," "),c=n.findIndex(l=>l.who===i&&(s&&l.t?l.t===s:l.flat.startsWith(u)||u.startsWith(l.flat)));if(c>=0){o.length>n[c].text.length&&(n[c]={...n[c],match:r,text:o,flat:u});continue}n.push({who:i,t:s,match:r,text:o,flat:u})}return n.slice(-Math.max(1,t)).map(r=>r.match)}function Q(e=[]){return P(e,{max:Number.MAX_SAFE_INTEGER}).map(t=>String(t?.segment?.text||t?.why||"").trim()).filter(Boolean)}function oe(e=[],{noun:t="matches",max:n=3,chars:r=180}={}){const o=(e||[]).filter(Boolean);if(!o.length)return"";if(o.length===1)return String(o[0].why||"")||p(o[0]?.segment?.text,r);const i=Q(o);if(!i.length)return`${o.length} ${t}`;const s=i.slice(0,n),u=Math.max(40,Math.floor(r/s.length)),c=i.length-s.length;return`${i.length} ${t}: ${s.map(l=>`“${p(l,u)}”`).join(" · ")}`+(c>0?` +${c} more`:"")}function ie(e,t,{registry:n,ctx:r={},admit:o=null}={}){const i=[];for(const s of e||[]){if(!s.enabled||o&&!o(s))continue;const u=n?.get(s.trigger);if(!u||u.kind==="timer"||u.watches.length&&!u.watches.includes(t?.type))continue;let c=null;try{c=u.matches(t,s.params,r)}catch{c=null}c&&i.push({job:s,trigger:u,match:c,key:x(s.id,t.at||t.t||0)})}return i}export{ee as BUILTIN_TRIGGERS,N as DANGLING_TAILS,K as DEFAULT_COALESCE_MAX,S as JOB_ACTIONS,D as MIN_PHRASE_CHARS,O as MISSED_POLICIES,T as SCHEDULE_KINDS,a as ScheduleError,v as TEXT_DELTA,k as TEXT_WATCHES,j as TRIGGER_KINDS,_ as TRIGGER_SOURCES,B as WEEKDAY_NAMES,p as clipText,P as coalesceMatches,V as createTriggerRegistry,te as defineJob,d as defineTrigger,Y as describeSchedule,ne as dueJobs,G as eventSource,ie as jobsForEvent,oe as matchSummary,Q as matchTexts,H as meetingEndedTrigger,W as meetingStartedTrigger,A as nextFireAt,re as nextWakeAt,x as occurrenceKey,L as occurrencesBetween,U as personJoinedTrigger,z as phraseTrigger,F as questionTrigger,R as saidIn,b as sourceAllowed,m as timerTrigger,J as topicTrigger,Z as utteranceLooksComplete,E as validateSchedule,X as voiceCommandTrigger};
1
+ class l extends Error{constructor(t,n){super(n),this.name="ScheduleError",this.code=t}}const O=Object.freeze(["once","interval","daily","weekly","cron"]),B=Object.freeze(["timer","meeting","voice","data","channel"]),D=Object.freeze(["skill","prompt","monitor","notify"]),C=Object.freeze(["skip","runOnce","runAll"]),E=20;function f(e,{days:t=0,hour:n,minute:r=0}){const o=new Date(e);return o.setDate(o.getDate()+t),o.setHours(n,r,0,0),o.getTime()}const L=e=>{const t=new Date(e).getDay();return t===0||t===6};function A(e){if(!e||typeof e!="object")throw new l("BAD_SCHEDULE","schedule must be an object");if(!O.includes(e.kind))throw new l("BAD_SCHEDULE",`unknown schedule kind '${e.kind}'`);if(e.kind==="once"&&!(e.at>0))throw new l("BAD_SCHEDULE","once needs `at`");if(e.kind==="interval"&&!(e.everyMs>=6e4))throw new l("BAD_SCHEDULE","interval needs everyMs >= 60000");if(e.kind==="daily"||e.kind==="weekly"){if(!Number.isInteger(e.hour)||e.hour<0||e.hour>23)throw new l("BAD_SCHEDULE","hour must be 0-23");const t=e.minute??0;if(!Number.isInteger(t)||t<0||t>59)throw new l("BAD_SCHEDULE","minute must be 0-59")}if(e.kind==="weekly"&&(!Number.isInteger(e.weekday)||e.weekday<0||e.weekday>6))throw new l("BAD_SCHEDULE","weekly needs weekday 0-6 (Sunday = 0)");return e.kind==="cron"&&p(e.expr),e}const I=Object.freeze([{name:"minute",min:0,max:59},{name:"hour",min:0,max:23},{name:"day-of-month",min:1,max:31},{name:"month",min:1,max:12,names:["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"]},{name:"day-of-week",min:0,max:7,names:["sun","mon","tue","wed","thu","fri","sat"]}]);function w(e,t){const n=e.toLowerCase();if(t.names){const o=t.names.indexOf(n.slice(0,3));if(o>=0&&n.length===3)return t.min===1?o+1:o}if(!/^\d+$/.test(n))throw new l("BAD_SCHEDULE",`cron: '${e}' is not a ${t.name}`);const r=Number(n);if(r<t.min||r>t.max)throw new l("BAD_SCHEDULE",`cron: ${t.name} ${r} is outside ${t.min}-${t.max}`);return r}function M(e,t){const n=new Set;for(const r of String(e).split(",")){if(!r)throw new l("BAD_SCHEDULE",`cron: empty entry in ${t.name}`);const[o,s]=r.split("/"),i=s===void 0?1:Number(s);if(!Number.isInteger(i)||i<1)throw new l("BAD_SCHEDULE",`cron: bad step '/${s}' in ${t.name}`);let c,a;if(o==="*")c=t.min,a=t.max;else if(o.includes("-")){const[u,h]=o.split("-");if(c=w(u,t),a=w(h,t),a<c)throw new l("BAD_SCHEDULE",`cron: range ${o} runs backwards in ${t.name}`)}else c=w(o,t),a=s===void 0?c:t.max;for(let u=c;u<=a;u+=i)n.add(u)}return t.name==="day-of-week"&&n.has(7)&&(n.delete(7),n.add(0)),n}function p(e){const t=String(e??"").trim().split(/\s+/);if(t.length!==5||!t[0])throw new l("BAD_SCHEDULE","cron needs five fields: minute hour day-of-month month day-of-week");const[n,r,o,s,i]=t.map((u,h)=>M(u,I[h])),c=t[2]==="*",a=t[4]==="*";return{minute:n,hour:r,dom:o,month:s,dow:i,domAny:c,dowAny:a}}const N=366*5;function H(e,t){const n=i=>{if(!e.month.has(i.getMonth()+1))return!1;const c=e.dom.has(i.getDate()),a=e.dow.has(i.getDay());return e.domAny&&e.dowAny?!0:e.domAny?a:e.dowAny?c:c||a},r=[...e.hour].sort((i,c)=>i-c),o=[...e.minute].sort((i,c)=>i-c),s=new Date(t);s.setSeconds(0,0);for(let i=0;i<N;i++){const c=new Date(s);if(c.setDate(s.getDate()+i),c.setHours(0,0,0,0),!!n(c))for(const a of r)for(const u of o){const h=new Date(c);if(h.setHours(a,u,0,0),h.getHours()===a&&h.getTime()>t)return h.getTime()}}return null}function _(e,t){const n=A(e),r=n.minute??0;switch(n.kind){case"once":return n.at>t?n.at:null;case"interval":{const o=n.anchor??t;if(o>t)return o;const s=Math.floor((t-o)/n.everyMs)+1;return o+s*n.everyMs}case"daily":{let o=f(t,{hour:n.hour,minute:r});if(o<=t&&(o=f(t,{days:1,hour:n.hour,minute:r})),n.weekdaysOnly)for(let s=0;s<7&&L(o);s++)o=f(o,{days:1,hour:n.hour,minute:r});return o}case"weekly":{const o=new Date(t).getDay();let s=(n.weekday-o+7)%7;return s===0&&f(t,{hour:n.hour,minute:r})<=t&&(s=7),f(t,{days:s,hour:n.hour,minute:r})}case"cron":return H(p(n.expr),t);default:return null}}const R=Object.freeze(["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]),y=e=>`${String(e?.hour??0).padStart(2,"0")}:${String(e?.minute??0).padStart(2,"0")}`;function re(e){if(!e||typeof e!="object")return"";switch(e.kind){case"once":return e.at>0?`once, at ${new Date(e.at).toLocaleString()}`:"";case"interval":{const t=Number(e.everyMs)||0;if(t<6e4)return"";const n=Math.round(t/6e4);if(n%1440===0){const r=n/1440;return`every ${r===1?"day":`${r} days`}`}if(n%60===0){const r=n/60;return`every ${r===1?"hour":`${r} hours`}`}return`every ${n} minutes`}case"daily":return e.weekdaysOnly?`every weekday at ${y(e)}`:`every day at ${y(e)}`;case"weekly":{const t=R[e.weekday];return t?`every ${t} at ${y(e)}`:""}case"cron":{try{p(e.expr)}catch{return""}return`on the cron schedule ${String(e.expr).trim()}`}default:return""}}function v(e,t,n,r=E){const o=[];let s=t;for(;o.length<r;){const i=_(e,s);if(i===null||i>n)break;o.push(i),s=i}return o}function m({id:e,label:t,kind:n,watches:r=[],description:o="",classUsed:s="R",matches:i=null,params:c={}}){if(!e)throw new l("BAD_TRIGGER","trigger.id required");if(!B.includes(n))throw new l("BAD_TRIGGER",`trigger '${e}': unknown kind '${n}'`);if(n!=="timer"&&typeof i!="function")throw new l("BAD_TRIGGER",`trigger '${e}': an event trigger needs matches()`);return Object.freeze({id:e,label:t||e,kind:n,watches:Object.freeze([...r]),description:o,classUsed:s,matches:i,params:Object.freeze({...c})})}function oe(e=[]){const t=[...e];return{add(n){return t.push(n),()=>{const r=t.indexOf(n);r>=0&&t.splice(r,1)}},list:()=>[...t],get:n=>t.find(r=>r.id===n)||null}}const U=e=>String(e||"").toLowerCase().match(/[\p{L}\p{N}']+/gu)||[],d=e=>String(e||"").trim().toLowerCase(),T=3,G=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");function x(e,t=120){const n=String(e||"").replace(/\s+/g," ").trim();if(n.length<=t)return n;const r=n.slice(0,t),o=r.lastIndexOf(" ");return`${(o>t*.6?r.slice(0,o):r).replace(/[\s,;:.!?—-]+$/,"")}…`}function W(e,t){const n=d(t);if(n.length<T)return!1;const r=/[\p{L}\p{N}]/u.test(n[0])?"\\b":"",o=/[\p{L}\p{N}]/u.test(n[n.length-1])?"\\b":"";try{return new RegExp(`${r}${G(n)}${o}`,"iu").test(String(e||""))}catch{return d(e).includes(n)}}function b(e,t,n){return e==="me"?!!n?.isSelf?.(t):e==="others"?!n?.isSelf?.(t):!0}const z=Object.freeze(new Set(["and","or","but","so","because","cause","cos","since","although","though","while","whereas","unless","until","if","when","whenever","that","which","who","whom","whose","than","as","like","what","to","of","in","on","at","by","for","from","with","without","about","into","onto","over","under","between","through","during","against","per","a","an","the","my","our","your","their","its","is","are","was","were","be","been","being","am","do","does","did","have","has","had","will","would","can","could","should","shall","may","might","must","um","uh","er"]));function ie(e){const t=String(e||"").trim();if(!t)return!1;if(/[.!?…]["'\u2019\u201d)\]]*$/.test(t))return!0;if(/[,;:\-\u2013\u2014]$/.test(t))return!1;const n=t.toLowerCase().match(/[\p{L}\p{N}']+/gu)||[],r=n[n.length-1];return r?!z.has(r):!0}const J="text.delta",j=Object.freeze(["meeting","note","chat"]),k=Object.freeze(["meeting.transcript.delta",J]);function q(e){if(e?.type==="meeting.transcript.delta")return"meeting";const t=d(e?.source);return j.includes(t)?t:""}function S(e,t){const n=q(t);if(!n)return!1;const r=(Array.isArray(e)?e:[]).map(d).filter(o=>j.includes(o));return r.length?r.includes(n):n==="meeting"}const g=m({id:"timer:schedule",label:"On a schedule",kind:"timer",description:'Once, on an interval, daily, or on a weekday — "every weekday at 8am".'}),F=m({id:"meeting:started",label:"When a meeting starts",kind:"meeting",watches:["meeting.started"],matches:(e,t={})=>t.platform&&d(e.platform)!==d(t.platform)||t.titleIncludes&&!d(e.title).includes(d(t.titleIncludes))?null:{why:`meeting started: ${e.title||e.meetingId}`}}),X=m({id:"meeting:ended",label:"When a meeting ends",kind:"meeting",watches:["meeting.ended"],matches:e=>({why:`meeting ended: ${e.title||e.meetingId}`})}),K=m({id:"meeting:person-joined",label:"When someone joins",kind:"meeting",watches:["meeting.person-joined"],matches:(e,t={})=>{const n=(t.names||[]).map(d).filter(Boolean),r=(e.people||[]).filter(o=>!n.length||n.some(s=>d(o)===s||d(o).startsWith(`${s} `)));return r.length?{why:`joined: ${r.join(", ")}`,people:r}:null}}),P=m({id:"meeting:phrase",label:"When a phrase is said",kind:"meeting",watches:k,matches:(e,t={},n={})=>{if(!S(t.sources,e))return null;const r=(t.any||[]).map(d).filter(o=>o.length>=T);if(!r.length)return null;for(const o of e.segments||[]){if(!b(t.speaker,o.speaker,n))continue;const s=r.find(i=>W(o.text,i));if(s)return{why:`“${s}” said by ${o.speaker||"someone"}`,segment:o,phrase:s}}return null}}),Y=m({id:"meeting:topic",label:"When someone talks about something",kind:"meeting",watches:k,matches:(e,t={},n={})=>{if(!S(t.sources,e))return null;const r=(t.terms||[]).map(d).filter(Boolean);if(!r.length)return null;const o=Math.max(1,Math.min(t.minHits||1,r.length)),s=(e.segments||[]).filter(a=>b(t.speaker,a.speaker,n)),i=new Set(s.flatMap(a=>U(a.text))),c=r.filter(a=>a.split(/\s+/).every(u=>i.has(u)));return c.length>=o?{why:`talking about ${c.join(", ")}`,terms:c}:null}}),Q=/^(who|what|when|where|why|how|which|whose|can|could|would|should|shall|do|does|did|is|are|was|were|will|have|has|any(one|body)|is there|are there)\b/i,V=m({id:"meeting:question",label:"When a question is asked",kind:"meeting",watches:k,matches:(e,t={},n={})=>{if(!S(t.sources,e))return null;for(const r of e.segments||[]){if(!b(t.speaker||"anyone",r.speaker,n))continue;const o=String(r.text||"").trim();if(!(o.length<8)&&(o.includes("?")||Q.test(o)))return{why:`question from ${r.speaker||"someone"}: “${x(o,100)}”`,segment:r}}return null}}),Z=m({id:"voice:command",label:"When you say the wake word",kind:"voice",watches:["voice.command"],matches:(e,t={})=>{const n=t.intents||[];return!e.command?.allowed||n.length&&!n.includes(e.command.intent)?null:{why:`you said “${e.command.command}”`,command:e.command}}}),se=Object.freeze([g,F,X,K,P,Y,V,Z]);function ce({id:e,name:t,trigger:n,schedule:r=null,params:o={},action:s,enabled:i=!0,onMissed:c="runOnce",limits:a={},approval:u=null,createdAt:h=0}){if(!e)throw new l("BAD_JOB","job.id required");if(!t)throw new l("BAD_JOB",`job '${e}': name required`);if(!n)throw new l("BAD_JOB",`job '${e}': trigger required`);if(!s||!D.includes(s.kind))throw new l("BAD_JOB",`job '${e}': action.kind must be one of ${D}`);if(s.kind==="skill"&&!s.skillId)throw new l("BAD_JOB",`job '${e}': skill action needs skillId`);if(!C.includes(c))throw new l("BAD_JOB",`job '${e}': unknown onMissed '${c}'`);return(n===g.id||r)&&A(r),{id:e,name:t,trigger:n,schedule:r,params:{...o},action:{...s},enabled:!!i,onMissed:c,limits:{...a},approval:u,createdAt:h||0}}function $(e,t){return`${e}@${t}`}function ae(e,{now:t,lastRun:n={},admit:r=null,max:o=E}={}){const s=[];for(const i of e||[]){if(!i.enabled||i.trigger!==g.id||!i.schedule||r&&!r(i))continue;const c=n[i.id]||i.createdAt||0;if(!c)continue;const a=v(i.schedule,c,t,o);if(!a.length)continue;const u=i.onMissed==="runAll"?a:i.onMissed==="runOnce"?[a[a.length-1]]:[];for(const h of u)s.push({job:i,at:h,key:$(i.id,h),late:t-h>6e4,missedCount:a.length});u.length||s.push({job:i,at:a[a.length-1],key:$(i.id,a[a.length-1]),skipped:!0,missedCount:a.length})}return s}function ue(e,{now:t,lastRun:n={}}={}){let r=null;for(const o of e||[]){if(!o.enabled||o.trigger!==g.id||!o.schedule)continue;const s=_(o.schedule,Math.max(t,n[o.id]||0));s!==null&&(r===null||s<r)&&(r=s)}return r}const ee=8;function te(e=[],{max:t=ee}={}){const n=[];for(const r of e){const o=String(r?.segment?.text||r?.why||"").trim();if(!o)continue;const s=d(r?.segment?.speaker),i=r?.segment?.t||0,c=o.toLowerCase().replace(/\s+/g," "),a=n.findIndex(u=>u.who===s&&(i&&u.t?u.t===i:u.flat.startsWith(c)||c.startsWith(u.flat)));if(a>=0){o.length>n[a].text.length&&(n[a]={...n[a],match:r,text:o,flat:c});continue}n.push({who:s,t:i,match:r,text:o,flat:c})}return n.slice(-Math.max(1,t)).map(r=>r.match)}function ne(e=[]){return te(e,{max:Number.MAX_SAFE_INTEGER}).map(t=>String(t?.segment?.text||t?.why||"").trim()).filter(Boolean)}function le(e=[],{noun:t="matches",max:n=3,chars:r=180}={}){const o=(e||[]).filter(Boolean);if(!o.length)return"";if(o.length===1)return String(o[0].why||"")||x(o[0]?.segment?.text,r);const s=ne(o);if(!s.length)return`${o.length} ${t}`;const i=s.slice(0,n),c=Math.max(40,Math.floor(r/i.length)),a=s.length-i.length;return`${s.length} ${t}: ${i.map(u=>`“${x(u,c)}”`).join(" · ")}`+(a>0?` +${a} more`:"")}function he(e,t,{registry:n,ctx:r={},admit:o=null}={}){const s=[];for(const i of e||[]){if(!i.enabled||o&&!o(i))continue;const c=n?.get(i.trigger);if(!c||c.kind==="timer"||c.watches.length&&!c.watches.includes(t?.type))continue;let a=null;try{a=c.matches(t,i.params,r)}catch{a=null}a&&s.push({job:i,trigger:c,match:a,key:$(i.id,t.at||t.t||0)})}return s}export{se as BUILTIN_TRIGGERS,z as DANGLING_TAILS,ee as DEFAULT_COALESCE_MAX,D as JOB_ACTIONS,T as MIN_PHRASE_CHARS,C as MISSED_POLICIES,O as SCHEDULE_KINDS,l as ScheduleError,J as TEXT_DELTA,k as TEXT_WATCHES,B as TRIGGER_KINDS,j as TRIGGER_SOURCES,R as WEEKDAY_NAMES,x as clipText,te as coalesceMatches,oe as createTriggerRegistry,ce as defineJob,m as defineTrigger,re as describeSchedule,ae as dueJobs,q as eventSource,he as jobsForEvent,le as matchSummary,ne as matchTexts,X as meetingEndedTrigger,F as meetingStartedTrigger,_ as nextFireAt,ue as nextWakeAt,$ as occurrenceKey,v as occurrencesBetween,p as parseCron,K as personJoinedTrigger,P as phraseTrigger,V as questionTrigger,W as saidIn,S as sourceAllowed,g as timerTrigger,Y as topicTrigger,ie as utteranceLooksComplete,A as validateSchedule,Z as voiceCommandTrigger};