bostrat-node 1.13.3 → 1.13.5
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/bin/bostrat-audit +4 -0
- package/dist/index.js +234 -223
- package/package.json +1 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import N from"node:fs/promises";import he from"node:os";import x from"node:path";var X={Workflow:216e5,Agent:36e5},z=5*6e4,j=80,$=3,Q=["Checkpoint: write a work-in-progress handoff","Resume from .bostrat/handoff/latest.md","Beat: write a","You are a SUBTASK agent working in an isolated","A subtask box you delegated has finished"],R={operator:"strong",orchestrator:"strong","background-job":"strong","task-continuation":"strong","operator-terminal":"weak","orchestrator-unlogged":"weak","background-launch":"weak","task-continuation-unlogged":"weak",peer:"flagged","nested-session":"flagged","unknown-prompt":"flagged",unrooted:"flagged"},E=e=>String(e??"").replace(/\s+/g," ").trim(),l=e=>e?.ts??0,D=(e,s)=>!!e&&!!s&&(e.startsWith(s.slice(0,j))||s.startsWith(e.slice(0,j))),Z=6,ee=(e,s)=>D(e,s)||e.length>=Z&&s.includes(e.slice(0,j)),te=/^<pasted_content\b[^>]*>\s*/i,v=e=>E(e.payload?.promptHead??e.payload?.text).replace(te,""),oe=/^<cross-session-message\b/i,ne=/^<task-notification>/i,se=/<tool-use-id>\s*([^<\s]+)\s*<\/tool-use-id>/i;function re(e){let s=e.payload||{},r=s.head||s.path||(s.command?E(s.command):"");return`${s.tool||"tool"}${r?`: ${r.slice(0,100)}`:""}`}function ie(e){let s={events:e.length,firstSeq:null,lastSeq:null,headMissing:!1,gaps:0,repeats:0},r=null;for(let a of e)Number.isFinite(a?.seq)&&(r===null?s.firstSeq=a.seq:a.seq>r+1?s.gaps++:a.seq<=r&&s.repeats++,r=a.seq);return s.lastSeq=r,s.headMissing=s.firstSeq!==null&&s.firstSeq>1,s}function ae(e){let s=new Map,r=new Map,a=new Map,n=new Map,c=(t,f,b)=>{t.has(f)||t.set(f,[]),t.get(f).push(b)};for(let t of e)if((t.type==="box.state.changed"||t.type.startsWith("handoff."))&&c(n,t.payload?.box||t.boxId||null,l(t)),t.type==="session.ready"&&([...n.get(t.boxId)||[],...n.get(null)||[]].some(b=>b<=l(t)&&l(t)-b<=12e4)||c(a,t.boxId,l(t))),t.type==="turn.user")if(t.source==="orchestrator"){let f=(t.payload?.attachments||[]).map(b=>b?.id).filter(Boolean);c(s,t.boxId,{ts:l(t),head:E(t.payload?.text),files:f,actor:t.actor,usedAt:null})}else t.source==="transcript"&&c(r,t.boxId,{ts:l(t),head:E(t.payload?.text),note:t.payload?.note?.kind||null});let i=new Map,p=new Map,m=new Map;for(let t of e){if(t.type==="turn.user"&&t.source==="orchestrator"&&p.set(t.boxId,!0),t.source!=="hook")continue;if(t.type==="turn.agent"){let k=m.get(t.boxId)||0;k>0?m.set(t.boxId,k-1):p.set(t.boxId,!1);continue}if(t.type!=="turn.user")continue;let f=v(t),b=(()=>{if(t.actor==="peer"||oe.test(f))return{origin:"peer"};if(ne.test(f))return{origin:"task-continuation",jobId:f.match(se)?.[1]||null};let k=(s.get(t.boxId)||[]).filter(u=>(u.usedAt===null||l(t)-u.usedAt<=5e3)&&u.ts>=l(t)-72e5&&u.ts<=l(t)+2e3&&(ee(u.head,f)||!u.head&&u.files.length>0&&(u.files.some(o=>f.includes(`.bostrat/uploads/${o}`))||l(t)-u.ts<=5e3))),S=k[k.length-1];if(S)return S.usedAt=l(t),{origin:S.actor==="orchestrator"?"orchestrator":"operator"};if(Q.some(u=>f.startsWith(u)))return{origin:"orchestrator-unlogged"};if((r.get(t.boxId)||[]).find(u=>!u.note&&u.ts>=l(t)-2e3&&u.ts<=l(t)+12e4&&D(u.head,f)))return{origin:"operator-terminal"};let _=(a.get(t.boxId)||[]).some(u=>u<=l(t)&&l(t)-u<=5e3);return{origin:p.get(t.boxId)||_?"nested-session":"unknown-prompt"}})();i.set(t,b),b.origin==="nested-session"?m.set(t.boxId,(m.get(t.boxId)||0)+1):p.set(t.boxId,!0)}return i}function ce(e){let s=new Map,r=new Map;for(let a of e){let n=a.payload?.id;if(n)if(a.type==="job.started"){let c={from:(a.payload?.ts??l(a))-5e3,to:1/0,loggedAt:l(a)};r.set(n,c),s.has(a.boxId)||s.set(a.boxId,[]),s.get(a.boxId).push(c)}else a.type==="job.stopped"&&r.has(n)&&(r.get(n).to=l(a)+5e3)}return{byBox:s,byId:r}}function de(e,{trackId:s=null,name:r=null,since:a=0}={}){let n=ae(e),c=ce(e),i=new Set;for(let o of e)o.type==="tool.called"&&o.source==="hook"&&i.add(o.boxId);let p=o=>o.type==="tool.called"&&(o.source==="hook"||!(o.provider==="claude"&&i.has(o.boxId))),m={},t={},f=new Map,b=(o,d,w,y,M)=>{let g=`${o}\0${w.boxId}\0${y}`,h=f.get(g);return(!h||l(w)-h.to>z)&&(h={rule:o,severity:d,trackId:s,track:r,boxId:w.boxId,from:l(w),to:l(w),count:0,note:M,samples:[]},f.set(g,h),k.push(h)),h.to=l(w),h.count++,h},k=[],S=new Map,C=o=>(S.has(o)||S.set(o,{open:!1,origin:null,nested:0,soft:null,lastSendHead:null,launch:null}),S.get(o));for(let o of e){let d=C(o.boxId),w=l(o)>=a;if(o.type==="turn.user"&&o.source==="hook"){let g=n.get(o);if(g.origin==="nested-session"){if(d.nested++,w){let h=b("nested-session","medium",o,"","a prompt no recorded send accounts for arrived mid-turn or right after a SessionStart \u2014 typically an agent-launched `claude -p`");h.samples.length<$&&h.samples.push(v(o).slice(0,100))}continue}if(d.open=!0,d.origin=g.origin,g.origin==="task-continuation"&&!c.byId.has(g.jobId)&&(d.origin="task-continuation-unlogged"),d.origin==="unknown-prompt"&&w){let h=b("unknown-prompt","medium",o,"","a turn opened by a prompt with no operator, machinery or job record behind it");h.samples.length<$&&h.samples.push(v(o).slice(0,100))}}else if(o.type==="turn.agent"&&o.source==="hook")d.nested>0?d.nested--:d.open=!1;else if(o.type==="turn.aborted"||o.type==="turn.interrupted")d.open=!1;else if(o.type==="turn.user"&&o.source==="orchestrator")d.lastSendHead=E(o.payload?.text),d.soft=o.actor==="orchestrator"?"orchestrator":"operator",d.open=!0,d.origin=d.soft;else if(o.type==="turn.user"&&o.source==="transcript"){let g=E(o.payload?.text);!o.payload?.note&&!D(g,d.lastSendHead)&&(d.soft="operator-terminal")}else o.type==="peer.message"&&(d.soft="peer");if(!p(o))continue;let y;if(o.source==="hook"){let g=(c.byBox.get(o.boxId)||[]).some(A=>l(o)>=A.from&&l(o)<=A.to);d.open?y=d.origin:g?y="background-job":d.nested>0?y="nested-session":d.launch&&l(o)<=d.launch?y="background-launch":y="unrooted";let h=o.payload?.tool,V=(c.byBox.get(o.boxId)||[]).some(A=>A.loggedAt<=l(o)+5e3);(h==="Workflow"||h==="Agent"&&!V)&&d.open&&R[d.origin]!=="flagged"&&(d.launch=Math.max(d.launch||0,l(o)+X[h]))}else y=d.soft||"unrooted";if(!w)continue;m[y]=(m[y]||0)+1;let M=o.provider||"unknown";if(t[M]||={actions:0,fidelity:o.source==="hook"?"hook":"transcript"},t[M].actions++,o.source==="hook"&&(t[M].fidelity="hook"),y==="unrooted"){let g=b("unrooted-actions","high",o,"","tool calls with no open turn, no recorded job and no launch that accounts for them");g.samples.length<$&&g.samples.push(re(o))}else if(y==="peer")b("peer-driven-actions","low",o,"","tool calls in a turn another session's message opened");else if(y==="nested-session"||y==="unknown-prompt"){let g=f.get(`${y}\0${o.boxId}\0`);g&&(g.actions=(g.actions||0)+1)}}let _=ie(e),u=Object.values(m).reduce((o,d)=>o+d,0);return _.headMissing&&u&&k.push({rule:"log-head-missing",severity:"medium",trackId:s,track:r,boxId:null,from:l(e[0]),to:l(e[0]),count:1,samples:[],note:`the log starts at seq ${_.firstSeq} \u2014 its earlier history is not on this node`}),{trackId:s,track:r,actions:u,byOrigin:m,byProvider:t,findings:k,integrity:_}}var B={high:0,medium:1,low:2};function Y(e,{days:s=14,now:r=Date.now()}={}){let a=s?r-s*864e5:0,n={days:s||null,tracks:0,actions:0,byOrigin:{},byStrength:{strong:0,weak:0,flagged:0},byProvider:{},findings:[],integrity:{logs:0,headMissing:0,withGaps:0,withRepeats:0}};for(let c of e||[]){let i=de(c.events||[],{trackId:c.trackId,name:c.name,since:a});if(n.integrity.logs++,i.integrity.headMissing&&n.integrity.headMissing++,i.integrity.gaps&&n.integrity.withGaps++,i.integrity.repeats&&n.integrity.withRepeats++,!(!i.actions&&!i.findings.length)){n.tracks++,n.actions+=i.actions;for(let[p,m]of Object.entries(i.byOrigin))n.byOrigin[p]=(n.byOrigin[p]||0)+m,n.byStrength[R[p]||"flagged"]+=m;for(let[p,m]of Object.entries(i.byProvider))n.byProvider[p]||={actions:0,fidelity:m.fidelity},n.byProvider[p].actions+=m.actions,m.fidelity==="hook"&&(n.byProvider[p].fidelity="hook");n.findings.push(...i.findings)}}return n.findings.sort((c,i)=>B[c.severity]-B[i.severity]||i.to-c.to),n.ok=!n.findings.some(c=>c.severity==="high"),n}var L=(e,s)=>s?`${(e/s*100).toFixed(e&&e/s<.001?2:1)}%`:"0%",T=e=>new Date(e).toISOString().slice(0,16).replace("T"," ");function J(e,{limit:s=20}={}){let r=[];r.push(`AGENT ACTION AUDIT \xB7 ${e.days?`last ${e.days}d`:"all history"} \xB7 ${e.actions} action(s) across ${e.tracks} Track(s)`),r.push(""),r.push("Who asked for it");for(let n of["strong","weak","flagged"]){let c=Object.entries(e.byOrigin).filter(([i])=>(R[i]||"flagged")===n).sort((i,p)=>p[1]-i[1]);if(c.length){r.push(` ${n.toUpperCase()} \xB7 ${e.byStrength[n]} (${L(e.byStrength[n],e.actions)})`);for(let[i,p]of c)r.push(` ${i.padEnd(27)} ${String(p).padStart(7)} ${L(p,e.actions)}`)}}r.push(""),r.push("Evidence by provider");for(let[n,c]of Object.entries(e.byProvider).sort((i,p)=>p[1].actions-i[1].actions))r.push(` ${n.padEnd(10)} ${String(c.actions).padStart(7)} `+(c.fidelity==="hook"?"hook-recorded (turn boundaries known)":"transcript only (agent-written; no turn boundaries)"));r.push("");let a=e.integrity;if(r.push(`Log integrity \xB7 ${a.logs} log(s): ${a.headMissing} missing their head, ${a.withGaps} with seq gaps, ${a.withRepeats} with repeated seq (informational until the hash chain lands)`),r.push(""),!e.findings.length)r.push("Findings: none.");else{r.push(`Findings \xB7 ${e.findings.length}`);for(let n of e.findings.slice(0,s)){let c=n.to-n.from>6e4?`${T(n.from)} \u2192 ${T(n.to).slice(11)}`:T(n.from),i=n.actions?`${n.count} prompt(s), ${n.actions} action(s)`:`${n.count}`;r.push(` [${n.severity}] ${n.rule} \xB7 ${n.track||n.trackId}${n.boxId?` \xB7 ${n.boxId}`:""} \xB7 ${c} \xB7 ${i}`),r.push(` ${n.note}`);for(let p of n.samples)r.push(` - ${p}`)}e.findings.length>s&&r.push(` \u2026 ${e.findings.length-s} more (--json for all)`)}return r.push(""),r.push(e.ok?"No action without an origin. The log is agent-writable, so this is evidence, not proof.":"Actions with NO origin were found \u2014 read the [high] findings above."),r.join(`
|
|
3
|
+
`)}import le from"node:path";import pe from"node:os";import{EventEmitter as ue}from"node:events";var fe=new ue;fe.setMaxListeners(0);var Ee=process.env.BOSTRAT_STATE_DIR||le.join(process.env.HOME||pe.tmpdir(),".bostrat");var ge=/(?<!\\)((?:\\\\)*)\\u0000/g,U=e=>e.includes("\\u0000"),K=e=>e.replace(ge,"$1\\ufffd");var O=process.env.BOSTRAT_STATE_DIR||x.join(process.env.HOME||he.tmpdir(),".bostrat"),I=process.argv.slice(2),F=e=>{let s=I.indexOf(e);return s>=0?I[s+1]:null};(I.includes("--help")||I.includes("-h"))&&(console.log("usage: bostrat-audit [--days N | --all] [--track <id-or-name>] [--limit N] [--json]"),process.exit(0));var H=[];try{H=JSON.parse(await N.readFile(x.join(O,"tracks.json"),"utf8")).tracks||[]}catch{}var me=new Map(H.map(e=>[e.id,e.name])),P=new Set([x.join(O,"events")]);for(let e of H)e.cwd&&P.add(x.join(e.cwd,".bostrat","events"));try{for(let e of await N.readdir(x.join(O,"workspaces")))P.add(x.join(O,"workspaces",e,".bostrat","events"))}catch{}var W=F("--track"),G=[];for(let e of P){let s=[];try{s=(await N.readdir(e)).filter(r=>r.endsWith(".ndjson"))}catch{continue}for(let r of s){let a=r.slice(0,-7),n=me.get(a)||null;if(W&&a!==W&&!(n||"").toLowerCase().includes(W.toLowerCase()))continue;let c=[];for(let i of(await N.readFile(x.join(e,r),"utf8")).split(`
|
|
4
|
+
`))if(i.trim())try{c.push(JSON.parse(U(i)?K(i):i))}catch{}c.length&&G.push({trackId:a,name:n,events:c})}}var ye=I.includes("--all")?0:Number(F("--days"))||14,q=Y(G,{days:ye});console.log(I.includes("--json")?JSON.stringify(q,null,2):J(q,{limit:Number(F("--limit"))||20}));process.exit(q.ok?0:2);
|