@xeno-corporation/xeno-agent-sdk 0.6.3 → 0.6.4

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.
@@ -1,4 +1,4 @@
1
- import{randomUUID as J}from"crypto";import{appendFileSync as M,existsSync as y,mkdirSync as d,readFileSync as x,readdirSync as U,renameSync as z,rmSync as j,writeFileSync as l}from"fs";import{homedir as q}from"os";import{basename as P,dirname as L,join as u,resolve as B}from"path";var f="0.6.3";import{mkdirSync as O,readFileSync as V,rmSync as v,writeFileSync as _}from"fs";import{hostname as k}from"os";import{dirname as N}from"path";function b(){return new Date().toISOString()}function I(){return new Date(Date.now()-Math.floor(process.uptime()*1e3)).toISOString()}function w(r){try{return JSON.parse(V(r,"utf8"))}catch{return null}}function T(r){if(!r||r<=0)return!1;try{return process.kill(r,0),!0}catch{return!1}}function F(r){return r.hostname!==k()?!0:T(r.pid)}function h(r,t){O(N(r),{recursive:!0}),_(r,JSON.stringify(t,null,2)+`
1
+ import{randomUUID as J}from"crypto";import{appendFileSync as M,existsSync as y,mkdirSync as d,readFileSync as x,readdirSync as U,renameSync as z,rmSync as j,writeFileSync as l}from"fs";import{homedir as q}from"os";import{basename as P,dirname as L,join as u,resolve as B}from"path";var f="0.6.4";import{mkdirSync as O,readFileSync as V,rmSync as v,writeFileSync as _}from"fs";import{hostname as k}from"os";import{dirname as N}from"path";function b(){return new Date().toISOString()}function I(){return new Date(Date.now()-Math.floor(process.uptime()*1e3)).toISOString()}function w(r){try{return JSON.parse(V(r,"utf8"))}catch{return null}}function T(r){if(!r||r<=0)return!1;try{return process.kill(r,0),!0}catch{return!1}}function F(r){return r.hostname!==k()?!0:T(r.pid)}function h(r,t){O(N(r),{recursive:!0}),_(r,JSON.stringify(t,null,2)+`
2
2
  `,{encoding:"utf8",flag:"wx"})}function $(r,t){let e=w(r);e?.pid!==t.pid||e.hostname!==t.hostname||v(r,{force:!0})}function S(r,t,e){let n=b(),s={schemaVersion:1,name:t,pid:process.pid,hostname:k(),processStartedAt:I(),version:e,acquiredAt:n,updatedAt:n};try{h(r,s)}catch(a){if(a.code!=="EEXIST")throw a;let c=w(r);if(c&&F(c))throw new Error(`${t} is already locked by PID ${c.pid} on ${c.hostname}.`);v(r,{force:!0}),h(r,s)}return{record:s,release:()=>{$(r,s)}}}var D=1,H=u(q(),".xeno-agent"),W=u(process.env.XENO_AGENT_HOME??H,"daemon"),A=u(W,"runs");function i(){return new Date().toISOString()}function G(r=new Date){return r.toISOString().replace(/[^0-9]/g,"").slice(0,14)}function R(r){return r.replace(/[^A-Za-z0-9_.-]/g,"_").slice(0,80)}function p(r){return B(r)}function g(r){return p(r).toLowerCase()}function C(r,t){let e=g(r),n=g(t);return e===n||e.startsWith(`${n}\\`)||e.startsWith(`${n}/`)}function K(r,t){return!!(g(r.cwd)===g(t)||r.git?.root&&C(t,r.git.root)||r.git?.worktree&&C(t,r.git.worktree))}function X(r){return R(Buffer.from(p(r)).toString("base64url"))}function Z(){return{input:0,output:0,total:0}}function m(r){try{return JSON.parse(x(r,"utf8"))}catch{return null}}function Q(r,t){d(L(r),{recursive:!0});let e=`${r}.${process.pid}.${Date.now()}.tmp`;l(e,JSON.stringify(t,null,2)+`
3
3
  `,"utf8"),z(e,r)}function Y(r){if(!r||r<=0)return!1;try{return process.kill(r,0),!0}catch{return!1}}function tt(r){return r==="completed"||r==="failed"||r==="cancelled"||r==="interrupted"}function et(r,t){return r.pinned!==t.pinned?r.pinned?-1:1:Date.parse(t.updatedAt)-Date.parse(r.updatedAt)}function mt(){return A}function Rt(r){return u(A,r)}function rt(r=new Date){return`run_${G(r)}_${J().slice(0,8)}`}var E=class{constructor(t=A){this.runsDir=t;d(this.runsDir,{recursive:!0})}runsDir;create(t){let e=rt(),n=u(this.runsDir,e);d(n,{recursive:!0});let s=i(),a=u(n,"events.jsonl"),o={schemaVersion:D,runId:e,sessionId:e,rootRunId:e,cwd:p(t.cwd),workspaceId:X(t.cwd),prompt:t.prompt,...t.title?{title:t.title}:{},status:"starting",model:t.model,...t.effort?{effort:t.effort}:{},...t.agent?{agent:t.agent}:{},...t.git?{git:t.git}:{},permissionMode:t.permissionMode,...t.cliVersion?{createdByCliVersion:t.cliVersion}:{},createdBySdkVersion:t.sdkVersion??f,createdAt:s,updatedAt:s,lastActivityAt:s,pinned:!!t.pinned,attachedClients:0,...t.cliVersion?{cliVersion:t.cliVersion}:{},...t.sdkVersion?{sdkVersion:t.sdkVersion}:{},stdoutPath:u(n,"stdout.log"),stderrPath:u(n,"stderr.log"),eventsPath:a,usage:Z(),children:[],tags:[]};return l(o.stdoutPath,"","utf8"),l(o.stderrPath,"","utf8"),l(o.eventsPath,"","utf8"),this.write(o),this.appendEvent(e,"run_created",{cwd:o.cwd,model:o.model,...o.agent?{agent:o.agent}:{},...o.git?{git:o.git}:{},permissionMode:o.permissionMode,pinned:o.pinned}),o}get(t){let e=m(this.recordPath(t));return e?this.refreshRecordStatus(e):null}list(t={}){if(!y(this.runsDir))return[];let e=U(this.runsDir,{withFileTypes:!0}).filter(n=>n.isDirectory()).map(n=>this.get(n.name)).filter(n=>n!==null).filter(n=>t.all||!t.cwd||K(n,t.cwd)).filter(n=>!t.status||t.status.includes(n.status)).sort(et);return typeof t.limit=="number"&&t.limit>0?e.slice(0,t.limit):e}markSpawned(t,e,n){return this.update(t,s=>({...s,status:"running",workerPid:e,...n?{workerVersion:n}:{},startedAt:s.startedAt??i(),lastActivityAt:i()}))}markStarted(t,e){return this.update(t,n=>({...n,status:"running",workerPid:e.pid,...e.workerVersion?{workerVersion:e.workerVersion}:{},...e.model?{model:e.model}:{},...e.effort?{effort:e.effort}:{},startedAt:n.startedAt??i(),lastActivityAt:i()}))}markCompleted(t,e){return this.update(t,n=>({...n,status:e.status,...e.statusReason?{statusReason:e.statusReason}:{},exitCode:e.exitCode??null,usage:e.usage??n.usage,endedAt:i(),lastActivityAt:i()}))}markCancelled(t,e){return this.update(t,n=>({...n,status:"cancelled",statusReason:e,endedAt:i(),lastActivityAt:i()}))}markPaused(t,e="Paused by user."){let n=this.update(t,s=>({...s,status:"paused",statusReason:e,lastActivityAt:i()}));return n&&this.appendEvent(t,"run_paused",{reason:e}),n}markResumed(t,e="Resumed by user."){let n=this.update(t,s=>{let a={...s,status:"running",statusReason:e,lastActivityAt:i()};return delete a.endedAt,delete a.exitCode,a});return n&&this.appendEvent(t,"run_resumed",{reason:e}),n}setPinned(t,e){let n=this.update(t,s=>({...s,pinned:e,lastActivityAt:i()}));return n&&this.appendEvent(t,e?"run_pinned":"run_unpinned",{pinned:e}),n}appendEvent(t,e,n={}){let s=m(this.recordPath(t)),a=s?.eventsPath??u(this.runsDir,t,"events.jsonl");d(L(a),{recursive:!0});let o={schemaVersion:D,runId:t,type:e,timestamp:i(),payload:n};M(a,JSON.stringify(o)+`
4
4
  `,"utf8"),s&&this.update(t,c=>({...c,lastActivityAt:o.timestamp}))}readEvents(t){let e=this.get(t);return!e||!y(e.eventsPath)?[]:x(e.eventsPath,"utf8").split(/\r?\n/).map(n=>n.trim()).filter(Boolean).map(n=>{try{return JSON.parse(n)}catch{return null}}).filter(n=>n!==null)}delete(t){j(u(this.runsDir,t),{recursive:!0,force:!0})}refreshRecordStatus(t){if(tt(t.status))return t;if(t.workerPid&&!Y(t.workerPid)){let e={...t,status:"failed",statusReason:"Worker process is no longer running and did not record a terminal status.",endedAt:t.endedAt??i(),updatedAt:i()};return this.write(e),e}return t}update(t,e){let n=m(this.recordPath(t));if(!n)return null;let s=e(n);return s.updatedAt=i(),this.write(s),s}write(t){let e=S(u(this.runDir(t.runId),"run.lock"),`run:${t.runId}`,f);try{Q(this.recordPath(t.runId),t)}finally{e.release()}}recordPath(t){return u(this.runsDir,R(P(t)),"run.json")}runDir(t){return u(this.runsDir,R(P(t)))}};export{E as AgentRunStore,S as acquireControlPlaneLock,rt as createAgentRunId,Rt as getAgentRunDir,mt as getAgentRunStoreDir};
package/dist/index.d.ts CHANGED
@@ -340,7 +340,7 @@ interface AgentSandbox {
340
340
  name: string;
341
341
  };
342
342
  }
343
- declare const SDK_VERSION = "0.6.3";
343
+ declare const SDK_VERSION = "0.6.4";
344
344
  type AuditRiskLevel = "none" | "low" | "medium" | "high" | "critical";
345
345
  type AuditDecision = "allow" | "ask" | "deny";
346
346
  type AuditStatus = "ok" | "error";
package/dist/index.js CHANGED
@@ -1082,7 +1082,7 @@ ${n}`].filter(o=>o.trim().length>0).join(`
1082
1082
 
1083
1083
  ---
1084
1084
 
1085
- `));let y=n.systemPrompt??ig({cwd:e,model:t,date:n.date??new Date().toISOString().split("T")[0],identity:d,memory:g||void 0,sessionId:n.sessionId,executionMode:r}),h=n.dispatchAgent??(async b=>{let{createDelegatedXenoAgent:R}=await Promise.resolve().then(()=>(oo(),Kg)),{agent:S}=await R({cwd:e,apiKey:s,baseURL:o,model:t,...n.fallbackModels?{fallbackModels:n.fallbackModels}:{},...n.effort?{effort:n.effort}:{},maxTokens:Math.max(512,Math.min(n.maxTokens??Vg,4096)),maxIterations:Math.max(3,Math.min(n.maxIterations??Yg,12)),parentSystemPrompt:y,parentExecutionMode:r,subagentRole:"explorer",permissionEngine:u,...n.sandbox?{sandbox:n.sandbox}:{},...n.onPermissionRequest?{onPermissionRequest:n.onPermissionRequest}:{}}),k=()=>{S.cancelCurrentTurn()};if(b.signal?.aborted)throw k(),new Error("dispatch_agent was aborted before the helper started");b.signal?.addEventListener("abort",k,{once:!0});try{return{output:await S.run(b.prompt)}}finally{b.signal?.removeEventListener("abort",k)}}),x=n.toolRegistry??pe({cwd:e,askUser:n.askUser,dispatchAgent:h,...n.webSearchApiKey?{webSearchApiKey:n.webSearchApiKey}:{},...f?{memoryManager:f}:{},...n.validateToolInputs!==void 0?{validateInputs:n.validateToolInputs}:{}});return n.toolRegistry&&n.validateToolInputs!==void 0&&x.setValidateInputs(n.validateToolInputs),{agent:new bt({apiKey:s,baseURL:o,ollamaBaseURL:i,...l!==void 0?{apiRequestTimeoutMs:l}:{},model:t,...n.fallbackModels?{fallbackModels:n.fallbackModels}:{},...n.effort?{effort:n.effort}:{},maxTokens:n.maxTokens??Vg,maxIterations:n.maxIterations??Yg,systemPrompt:y,requesterLabel:n.requesterLabel,executionMode:r,permissionEngine:u,toolRegistry:x,sandbox:n.sandbox,onPermissionRequest:n.onPermissionRequest,onText:n.onText,onToolStart:n.onToolStart,onToolWillExecute:n.onToolWillExecute,onToolEnd:n.onToolEnd,onIteration:n.onIteration,onError:n.onError,onTranscriptError:n.onTranscriptError,onRuntimeEvent:n.onRuntimeEvent,runtimeEventBus:n.runtimeEventBus,turnDiffTracker:n.turnDiffTracker,onModeSwitchRequest:n.onModeSwitchRequest,onExecutionModeChanged:n.onExecutionModeChanged,completionGuard:n.completionGuard,maxCompletionGuardReminders:n.maxCompletionGuardReminders,progressGuardEveryIterations:n.progressGuardEveryIterations,...n.toolMiddleware?{toolMiddleware:n.toolMiddleware}:{},...n.promptSections?{promptSections:n.promptSections}:{},...n.promptSectionsTokenBudget!==void 0?{promptSectionsTokenBudget:n.promptSectionsTokenBudget}:{},...n.completionGuards?{completionGuards:n.completionGuards}:{},...n.provider?{provider:n.provider}:{},...n.session}),systemPrompt:y,permissionEngine:u,toolRegistry:x,...d?{identity:d}:{},...p?{memory:{resolved:p,...m?{projectSessionContext:m}:{},prompt:g}}:{}}}var Vg,Yg,sn=w(()=>{"use strict";je();Fe();Xs();cc();Vs();In();to();Ve();Vg=8192,Yg=50});It();var hn="0.6.3";se();ee();import{randomUUID as rh}from"crypto";var bn=class{filePath;sessionId;sequence=0;writeQueue=Promise.resolve();constructor(e){this.filePath=e.filePath,this.sessionId=e.sessionId}get path(){return this.filePath}async append(e){let t=rh(),r={id:t,sequence:this.sequence++,timestamp:new Date().toISOString(),session_id:e.session_id??this.sessionId,...e};return this.writeQueue=this.writeQueue.then(async()=>{await ot(this.filePath,JSON.stringify(r))}),await this.writeQueue,t}async read(e){let t=await B(this.filePath);if(!t)return[];let r=at(t);return e?.eventType&&(r=r.filter(s=>s.event_type===e.eventType)),e?.traceId&&(r=r.filter(s=>s.trace_id===e.traceId)),e?.limit!==void 0&&(r=r.slice(-Math.max(0,e.limit))),r}async tail(e=20){let t=Math.max(1,Math.min(e,500));return this.read({limit:t})}async exportJson(e){let t=await this.read();return await U(e,JSON.stringify(t,null,2)),t.length}async flush(){await this.writeQueue}};function sh(n,e){return e.endedAt.localeCompare(n.endedAt)}function bo(n,e){n.set(e,(n.get(e)??0)+1)}function vo(n,e){let t=Date.parse(n),r=Date.parse(e);return!Number.isFinite(t)||!Number.isFinite(r)?0:Math.max(0,r-t)}function Il(n){return n.filter(e=>e.tool_name||e.event_type.startsWith("tool_")).length}function Dl(n){return n.filter(e=>e.event_type==="permission_decision").length}function Ol(n){return n.filter(e=>e.status==="error"||e.event_type.endsWith("_failed")).length}function xo(n){return n.split(/[_\s-]+/).filter(e=>e.length>0).map(e=>e[0].toUpperCase()+e.slice(1)).join(" ")}function wo(n){if(!n)return;let e=Object.entries(n).filter(([,t])=>typeof t=="string"||typeof t=="number"||typeof t=="boolean").slice(0,3).map(([t,r])=>`${t}=${String(r)}`);return e.length>0?e.join(" | "):void 0}function oh(n){let e=[];for(let t=1;t<n.length;t+=1){let r=n[t-1],s=n[t],o=Date.parse(r.timestamp),i=Date.parse(s.timestamp),a=Number.isFinite(o)&&Number.isFinite(i)?Math.max(0,i-o):0;e.push({fromSequence:r.sequence,toSequence:s.sequence,fromEventType:r.event_type,toEventType:s.event_type,gapMs:a})}return e.sort((t,r)=>r.gapMs-t.gapMs).slice(0,5)}function ih(n){let e=xo(n.event_type),t=n.reason;if(n.event_type==="permission_decision")e=`${n.decision==="deny"?"Denied":"Approved"} ${n.tool_name??"tool"} permission`,t=n.reason;else if(n.tool_name&&n.event_type.startsWith("tool_"))e=`${xo(n.event_type)}: ${n.tool_name}`;else if(n.event_type==="delegation_completed"){let r=typeof n.metadata?.selected_from=="object"&&n.metadata?.selected_from?String(n.metadata.selected_from.role??"unknown"):void 0;e=r?`Delegation completed via ${r}`:"Delegation completed",t=wo(n.metadata)}else n.event_type==="delegation_started"?(e="Delegation started",t=wo(n.metadata)):n.tool_name?e=`${xo(n.event_type)}: ${n.tool_name}`:t||(t=wo(n.metadata));return{sequence:n.sequence,timestamp:n.timestamp,title:e,...t?{detail:t}:{},actor:n.actor,riskLevel:n.risk_level,...n.status?{status:n.status}:{}}}function So(n){let e=new Map;for(let r of n){let s=r.trace_id?.trim();if(!s)continue;let o=e.get(s);o?o.push(r):e.set(s,[r])}let t=[];for(let[r,s]of e.entries()){let o=[...s].sort((c,l)=>c.sequence-l.sequence),i=o[0]?.timestamp??"",a=o[o.length-1]?.timestamp??i;t.push({traceId:r,eventCount:o.length,startedAt:i,endedAt:a,durationMs:vo(i,a),toolEvents:Il(o),permissionEvents:Dl(o),errorEvents:Ol(o),lastEventType:o[o.length-1]?.event_type??"unknown"})}return t.sort(sh)}function ah(n,e){let t=So(n),r=e??t[0]?.traceId;if(!r)return null;let s=n.filter(d=>d.trace_id===r).sort((d,p)=>d.sequence-p.sequence);if(s.length===0)return null;let o=new Map,i=new Map,a=new Map,c=new Map;for(let d of s){if(bo(o,d.event_type),bo(a,d.actor),bo(c,d.risk_level),!d.tool_name)continue;let p=i.get(d.tool_name)??{toolName:d.tool_name,count:0,ok:0,error:0,denied:0};p.count+=1,d.status==="error"?p.error+=1:p.ok+=1,d.decision==="deny"&&(p.denied+=1),i.set(d.tool_name,p)}let l=s[0]?.timestamp??"",u=s[s.length-1]?.timestamp??l;return{traceId:r,eventCount:s.length,startedAt:l,endedAt:u,durationMs:vo(l,u),toolEvents:Il(s),permissionEvents:Dl(s),deniedPermissions:s.filter(d=>d.event_type==="permission_decision"&&d.decision==="deny").length,errorEvents:Ol(s),eventTypes:Object.fromEntries([...o.entries()].sort((d,p)=>d[0].localeCompare(p[0]))),actorSummary:Object.fromEntries([...a.entries()].sort((d,p)=>d[0].localeCompare(p[0]))),riskSummary:Object.fromEntries([...c.entries()].sort((d,p)=>d[0].localeCompare(p[0]))),toolSummary:[...i.values()].sort((d,p)=>d.toolName.localeCompare(p.toolName)),topLatencyGaps:oh(s),timeline:s.map(d=>({sequence:d.sequence,timestamp:d.timestamp,eventType:d.event_type,actor:d.actor,riskLevel:d.risk_level,...d.tool_name?{toolName:d.tool_name}:{},...d.decision?{decision:d.decision}:{},...d.status?{status:d.status}:{},...d.reason?{reason:d.reason}:{}}))}}function ch(n,e){let t=So(n),r=e??t[0]?.traceId;if(!r)return null;let s=n.filter(a=>a.trace_id===r).sort((a,c)=>a.sequence-c.sequence);if(s.length===0)return null;let o=s[0]?.timestamp??"",i=s[s.length-1]?.timestamp??o;return{traceId:r,startedAt:o,endedAt:i,durationMs:vo(o,i),steps:s.map(ih)}}function lh(n){if(n.length===0)return"No audit traces recorded.";let e=["Audit traces",""];for(let t of n)e.push(`${t.traceId} | ${t.eventCount} events | ${t.toolEvents} tool | ${t.permissionEvents} perms | ${t.errorEvents} errors | ${Math.round(t.durationMs/1e3)}s`);return e.join(`
1085
+ `));let y=n.systemPrompt??ig({cwd:e,model:t,date:n.date??new Date().toISOString().split("T")[0],identity:d,memory:g||void 0,sessionId:n.sessionId,executionMode:r}),h=n.dispatchAgent??(async b=>{let{createDelegatedXenoAgent:R}=await Promise.resolve().then(()=>(oo(),Kg)),{agent:S}=await R({cwd:e,apiKey:s,baseURL:o,model:t,...n.fallbackModels?{fallbackModels:n.fallbackModels}:{},...n.effort?{effort:n.effort}:{},maxTokens:Math.max(512,Math.min(n.maxTokens??Vg,4096)),maxIterations:Math.max(3,Math.min(n.maxIterations??Yg,12)),parentSystemPrompt:y,parentExecutionMode:r,subagentRole:"explorer",permissionEngine:u,...n.sandbox?{sandbox:n.sandbox}:{},...n.onPermissionRequest?{onPermissionRequest:n.onPermissionRequest}:{}}),k=()=>{S.cancelCurrentTurn()};if(b.signal?.aborted)throw k(),new Error("dispatch_agent was aborted before the helper started");b.signal?.addEventListener("abort",k,{once:!0});try{return{output:await S.run(b.prompt)}}finally{b.signal?.removeEventListener("abort",k)}}),x=n.toolRegistry??pe({cwd:e,askUser:n.askUser,dispatchAgent:h,...n.webSearchApiKey?{webSearchApiKey:n.webSearchApiKey}:{},...f?{memoryManager:f}:{},...n.validateToolInputs!==void 0?{validateInputs:n.validateToolInputs}:{}});return n.toolRegistry&&n.validateToolInputs!==void 0&&x.setValidateInputs(n.validateToolInputs),{agent:new bt({apiKey:s,baseURL:o,ollamaBaseURL:i,...l!==void 0?{apiRequestTimeoutMs:l}:{},model:t,...n.fallbackModels?{fallbackModels:n.fallbackModels}:{},...n.effort?{effort:n.effort}:{},maxTokens:n.maxTokens??Vg,maxIterations:n.maxIterations??Yg,systemPrompt:y,requesterLabel:n.requesterLabel,executionMode:r,permissionEngine:u,toolRegistry:x,sandbox:n.sandbox,onPermissionRequest:n.onPermissionRequest,onText:n.onText,onToolStart:n.onToolStart,onToolWillExecute:n.onToolWillExecute,onToolEnd:n.onToolEnd,onIteration:n.onIteration,onError:n.onError,onTranscriptError:n.onTranscriptError,onRuntimeEvent:n.onRuntimeEvent,runtimeEventBus:n.runtimeEventBus,turnDiffTracker:n.turnDiffTracker,onModeSwitchRequest:n.onModeSwitchRequest,onExecutionModeChanged:n.onExecutionModeChanged,completionGuard:n.completionGuard,maxCompletionGuardReminders:n.maxCompletionGuardReminders,progressGuardEveryIterations:n.progressGuardEveryIterations,...n.toolMiddleware?{toolMiddleware:n.toolMiddleware}:{},...n.promptSections?{promptSections:n.promptSections}:{},...n.promptSectionsTokenBudget!==void 0?{promptSectionsTokenBudget:n.promptSectionsTokenBudget}:{},...n.completionGuards?{completionGuards:n.completionGuards}:{},...n.provider?{provider:n.provider}:{},...n.session}),systemPrompt:y,permissionEngine:u,toolRegistry:x,...d?{identity:d}:{},...p?{memory:{resolved:p,...m?{projectSessionContext:m}:{},prompt:g}}:{}}}var Vg,Yg,sn=w(()=>{"use strict";je();Fe();Xs();cc();Vs();In();to();Ve();Vg=8192,Yg=50});It();var hn="0.6.4";se();ee();import{randomUUID as rh}from"crypto";var bn=class{filePath;sessionId;sequence=0;writeQueue=Promise.resolve();constructor(e){this.filePath=e.filePath,this.sessionId=e.sessionId}get path(){return this.filePath}async append(e){let t=rh(),r={id:t,sequence:this.sequence++,timestamp:new Date().toISOString(),session_id:e.session_id??this.sessionId,...e};return this.writeQueue=this.writeQueue.then(async()=>{await ot(this.filePath,JSON.stringify(r))}),await this.writeQueue,t}async read(e){let t=await B(this.filePath);if(!t)return[];let r=at(t);return e?.eventType&&(r=r.filter(s=>s.event_type===e.eventType)),e?.traceId&&(r=r.filter(s=>s.trace_id===e.traceId)),e?.limit!==void 0&&(r=r.slice(-Math.max(0,e.limit))),r}async tail(e=20){let t=Math.max(1,Math.min(e,500));return this.read({limit:t})}async exportJson(e){let t=await this.read();return await U(e,JSON.stringify(t,null,2)),t.length}async flush(){await this.writeQueue}};function sh(n,e){return e.endedAt.localeCompare(n.endedAt)}function bo(n,e){n.set(e,(n.get(e)??0)+1)}function vo(n,e){let t=Date.parse(n),r=Date.parse(e);return!Number.isFinite(t)||!Number.isFinite(r)?0:Math.max(0,r-t)}function Il(n){return n.filter(e=>e.tool_name||e.event_type.startsWith("tool_")).length}function Dl(n){return n.filter(e=>e.event_type==="permission_decision").length}function Ol(n){return n.filter(e=>e.status==="error"||e.event_type.endsWith("_failed")).length}function xo(n){return n.split(/[_\s-]+/).filter(e=>e.length>0).map(e=>e[0].toUpperCase()+e.slice(1)).join(" ")}function wo(n){if(!n)return;let e=Object.entries(n).filter(([,t])=>typeof t=="string"||typeof t=="number"||typeof t=="boolean").slice(0,3).map(([t,r])=>`${t}=${String(r)}`);return e.length>0?e.join(" | "):void 0}function oh(n){let e=[];for(let t=1;t<n.length;t+=1){let r=n[t-1],s=n[t],o=Date.parse(r.timestamp),i=Date.parse(s.timestamp),a=Number.isFinite(o)&&Number.isFinite(i)?Math.max(0,i-o):0;e.push({fromSequence:r.sequence,toSequence:s.sequence,fromEventType:r.event_type,toEventType:s.event_type,gapMs:a})}return e.sort((t,r)=>r.gapMs-t.gapMs).slice(0,5)}function ih(n){let e=xo(n.event_type),t=n.reason;if(n.event_type==="permission_decision")e=`${n.decision==="deny"?"Denied":"Approved"} ${n.tool_name??"tool"} permission`,t=n.reason;else if(n.tool_name&&n.event_type.startsWith("tool_"))e=`${xo(n.event_type)}: ${n.tool_name}`;else if(n.event_type==="delegation_completed"){let r=typeof n.metadata?.selected_from=="object"&&n.metadata?.selected_from?String(n.metadata.selected_from.role??"unknown"):void 0;e=r?`Delegation completed via ${r}`:"Delegation completed",t=wo(n.metadata)}else n.event_type==="delegation_started"?(e="Delegation started",t=wo(n.metadata)):n.tool_name?e=`${xo(n.event_type)}: ${n.tool_name}`:t||(t=wo(n.metadata));return{sequence:n.sequence,timestamp:n.timestamp,title:e,...t?{detail:t}:{},actor:n.actor,riskLevel:n.risk_level,...n.status?{status:n.status}:{}}}function So(n){let e=new Map;for(let r of n){let s=r.trace_id?.trim();if(!s)continue;let o=e.get(s);o?o.push(r):e.set(s,[r])}let t=[];for(let[r,s]of e.entries()){let o=[...s].sort((c,l)=>c.sequence-l.sequence),i=o[0]?.timestamp??"",a=o[o.length-1]?.timestamp??i;t.push({traceId:r,eventCount:o.length,startedAt:i,endedAt:a,durationMs:vo(i,a),toolEvents:Il(o),permissionEvents:Dl(o),errorEvents:Ol(o),lastEventType:o[o.length-1]?.event_type??"unknown"})}return t.sort(sh)}function ah(n,e){let t=So(n),r=e??t[0]?.traceId;if(!r)return null;let s=n.filter(d=>d.trace_id===r).sort((d,p)=>d.sequence-p.sequence);if(s.length===0)return null;let o=new Map,i=new Map,a=new Map,c=new Map;for(let d of s){if(bo(o,d.event_type),bo(a,d.actor),bo(c,d.risk_level),!d.tool_name)continue;let p=i.get(d.tool_name)??{toolName:d.tool_name,count:0,ok:0,error:0,denied:0};p.count+=1,d.status==="error"?p.error+=1:p.ok+=1,d.decision==="deny"&&(p.denied+=1),i.set(d.tool_name,p)}let l=s[0]?.timestamp??"",u=s[s.length-1]?.timestamp??l;return{traceId:r,eventCount:s.length,startedAt:l,endedAt:u,durationMs:vo(l,u),toolEvents:Il(s),permissionEvents:Dl(s),deniedPermissions:s.filter(d=>d.event_type==="permission_decision"&&d.decision==="deny").length,errorEvents:Ol(s),eventTypes:Object.fromEntries([...o.entries()].sort((d,p)=>d[0].localeCompare(p[0]))),actorSummary:Object.fromEntries([...a.entries()].sort((d,p)=>d[0].localeCompare(p[0]))),riskSummary:Object.fromEntries([...c.entries()].sort((d,p)=>d[0].localeCompare(p[0]))),toolSummary:[...i.values()].sort((d,p)=>d.toolName.localeCompare(p.toolName)),topLatencyGaps:oh(s),timeline:s.map(d=>({sequence:d.sequence,timestamp:d.timestamp,eventType:d.event_type,actor:d.actor,riskLevel:d.risk_level,...d.tool_name?{toolName:d.tool_name}:{},...d.decision?{decision:d.decision}:{},...d.status?{status:d.status}:{},...d.reason?{reason:d.reason}:{}}))}}function ch(n,e){let t=So(n),r=e??t[0]?.traceId;if(!r)return null;let s=n.filter(a=>a.trace_id===r).sort((a,c)=>a.sequence-c.sequence);if(s.length===0)return null;let o=s[0]?.timestamp??"",i=s[s.length-1]?.timestamp??o;return{traceId:r,startedAt:o,endedAt:i,durationMs:vo(o,i),steps:s.map(ih)}}function lh(n){if(n.length===0)return"No audit traces recorded.";let e=["Audit traces",""];for(let t of n)e.push(`${t.traceId} | ${t.eventCount} events | ${t.toolEvents} tool | ${t.permissionEvents} perms | ${t.errorEvents} errors | ${Math.round(t.durationMs/1e3)}s`);return e.join(`
1086
1086
  `)}function uh(n){let e=[`Audit trace ${n.traceId}`,`Started: ${n.startedAt}`,`Ended: ${n.endedAt}`,`Duration: ${n.durationMs} ms`,`Events: ${n.eventCount}`,`Tool events: ${n.toolEvents}`,`Permission events: ${n.permissionEvents}`,`Denied permissions: ${n.deniedPermissions}`,`Errors: ${n.errorEvents}`,"","Event types"];for(let[t,r]of Object.entries(n.eventTypes))e.push(` ${t}: ${r}`);e.push(""),e.push("Actors");for(let[t,r]of Object.entries(n.actorSummary))e.push(` ${t}: ${r}`);e.push(""),e.push("Risk levels");for(let[t,r]of Object.entries(n.riskSummary))e.push(` ${t}: ${r}`);if(e.push(""),e.push("Tools"),n.toolSummary.length===0)e.push(" (no tool activity)");else for(let t of n.toolSummary)e.push(` ${t.toolName}: ${t.count} total | ${t.ok} ok | ${t.error} error | ${t.denied} denied`);if(e.push(""),e.push("Largest gaps"),n.topLatencyGaps.length===0)e.push(" (no gaps)");else for(let t of n.topLatencyGaps)e.push(` #${t.fromSequence}->#${t.toSequence}: ${t.gapMs} ms | ${t.fromEventType} -> ${t.toEventType}`);e.push(""),e.push("Timeline");for(let t of n.timeline){let r=[t.eventType,t.toolName,t.decision,t.status,t.reason].filter(s=>typeof s=="string"&&s.length>0);e.push(` #${t.sequence} ${t.timestamp} | ${r.join(" | ")||t.eventType}`)}return e.join(`
1087
1087
  `)}function dh(n){return[`## Audit Trace ${n.traceId}`,"",`- Started: \`${n.startedAt}\``,`- Ended: \`${n.endedAt}\``,`- Duration: \`${n.durationMs}\` ms`,`- Events: \`${n.eventCount}\``,`- Tool events: \`${n.toolEvents}\``,`- Permission events: \`${n.permissionEvents}\``,`- Denied permissions: \`${n.deniedPermissions}\``,`- Errors: \`${n.errorEvents}\``,"","### Tool Summary","","| Tool | Total | OK | Error | Denied |","| --- | ---: | ---: | ---: | ---: |",...n.toolSummary.length>0?n.toolSummary.map(t=>`| ${t.toolName} | ${t.count} | ${t.ok} | ${t.error} | ${t.denied} |`):["| (none) | 0 | 0 | 0 | 0 |"],"","### Largest Gaps","","| From | To | Gap ms | Events |","| ---: | ---: | ---: | --- |",...n.topLatencyGaps.length>0?n.topLatencyGaps.map(t=>`| ${t.fromSequence} | ${t.toSequence} | ${t.gapMs} | ${t.fromEventType} -> ${t.toEventType} |`):["| 0 | 0 | 0 | none |"]].join(`
1088
1088
  `)}function ph(n){let e=[`## Audit Replay ${n.traceId}`,"",`- Started: \`${n.startedAt}\``,`- Ended: \`${n.endedAt}\``,`- Duration: \`${n.durationMs}\` ms`,""];for(let t of n.steps){let r=[t.actor,t.riskLevel,t.status].filter(Boolean).join(" | ");e.push(`- **#${t.sequence} ${t.title}**${r?` _(${r})_`:""}`),t.detail&&e.push(` - ${t.detail}`)}return e.join(`
@@ -42,7 +42,7 @@ ${this.stringify(t.data)}
42
42
  `)+`
43
43
  `;await p(this.transcriptPath,a);let l=this.buildMarkdownDocument(o,"session store");if(await p(this.markdownPath,l),!this.workspaceMirrorDisabled){let c=await this.resolveWorkspaceMarkdownPath();if(c)try{let m=this.buildMarkdownDocument(o,"workspace mirror");await p(c,m)}catch(m){this.workspaceMirrorDisabled=!0,S("Transcript workspace mirror disabled",m)}}}async truncateAfterMessageCount(t){let e=await u(this.transcriptPath);if(!e)return;let r=_(e),n=Math.max(0,t),i=0,o=[];for(let c of r){if(c.type==="user_message"||c.type==="assistant_message"){if(i>=n)break;i+=1}o.push(c)}let a=o.length>0?o.map(c=>JSON.stringify(c)).join(`
44
44
  `)+`
45
- `:"";await p(this.transcriptPath,a);let l=this.buildMarkdownDocument(o,"session store");if(await p(this.markdownPath,l),!this.workspaceMirrorDisabled){let c=await this.resolveWorkspaceMarkdownPath();if(c)try{let m=this.buildMarkdownDocument(o,"workspace mirror");await p(c,m)}catch(m){this.workspaceMirrorDisabled=!0,S("Transcript workspace mirror disabled",m)}}}getSequence(){return this.sequence}async initialize(){try{let t=await u(this.transcriptPath);if(!t){this.sequence=0;return}let e=_(t);if(e.length===0){this.sequence=0;return}let r=e[e.length-1];this.sequence=r.sequence+1}catch(t){let e=t instanceof Error?t.message:String(t);S(`Transcript initialization warning: ${e}. Starting with empty transcript.`),this.sequence=0}}async flush(){await this.writeQueue}};import*as O from"path";import{randomUUID as xt}from"crypto";var St={View:"Read",Replace:"Write",GlobTool:"Glob",GrepTool:"Grep",SQLiteAnalyze:"SqliteAnalyze",ReadNotebook:"NotebookRead",NotebookEditCell:"NotebookEdit"};function W(s){return St[s]??s}var I=class{sessionDir;checkpointsDir;autoInterval;lastCheckpointMessageCount=0;constructor(t,e){this.sessionDir=t,this.checkpointsDir=O.join(t,"checkpoints"),this.autoInterval=e?.autoInterval??10}async initialize(){let t=await this.list();t.length>0&&(this.lastCheckpointMessageCount=t[0].messageCount)}async create(t){await E(this.checkpointsDir);let e=xt(),r={id:e,name:t.description,trigger:t.trigger,createdAt:new Date().toISOString(),messageCount:t.messages.length,tokenCount:this.estimateTokens(t.messages)},n={info:r,messages:t.messages},i=O.join(this.checkpointsDir,`${e}.json`);return await p(i,JSON.stringify(n,null,2)),this.lastCheckpointMessageCount=t.messages.length,r}async list(){let t=await ot(this.checkpointsDir,/\.json$/),e=[];for(let r of t){let n=await u(r);if(n){let i=f(n,null);i&&e.push(i.info)}}return e.sort((r,n)=>new Date(n.createdAt).getTime()-new Date(r.createdAt).getTime())}async restore(t){let e=O.join(this.checkpointsDir,`${t}.json`),r;try{r=await u(e)}catch(i){let o=i instanceof Error?i.message:String(i);throw new Error(`Failed to read checkpoint ${t}: ${o}`)}if(!r)throw new Error(`Checkpoint not found: ${t} (path: ${e})`);let n=f(r,null);if(!n)throw new Error(`Invalid checkpoint data for ${t}: JSON parse failed`);if(!n.messages||!Array.isArray(n.messages))throw new Error(`Invalid checkpoint data for ${t}: missing or invalid messages array`);if(!n.info)throw new Error(`Invalid checkpoint data for ${t}: missing info object`);return{messages:n.messages,info:n.info}}shouldAutoCheckpoint(t){return t-this.lastCheckpointMessageCount>=this.autoInterval}static isDangerousOperation(t,e){if(t=W(t),t==="Write")return!0;if(t==="Bash"){let n=e.command?.toLowerCase()||"";return["rm ","del ","git push","git reset","drop ","truncate"].some(o=>n.includes(o))}return!1}async delete(t){let e=O.join(this.checkpointsDir,`${t}.json`);await k(e)}estimateTokens(t){let e=0;for(let r of t)if(typeof r.content=="string")e+=Math.ceil(r.content.length/4);else if(Array.isArray(r.content))for(let n of r.content)"text"in n&&(e+=Math.ceil(n.text.length/4));return e}};import*as x from"path";import*as Q from"os";import*as R from"fs";var K=new Set,ut=!1;function Pt(){for(let s of K)try{s()}catch{}}function pt(s){return K.add(s),!ut&&typeof process<"u"&&typeof process.on=="function"&&(ut=!0,process.on("exit",Pt)),()=>{K.delete(s)}}var dt="0.6.3";var vt=1e4,bt=6e4,Dt="session.lock",Et="lock.json",$=new Set;function Tt(){for(let s of $)try{R.unlinkSync(s)}catch{}$.clear()}pt(Tt);var M=class s{sessionDir;lockPath;legacyLockPath;sessionId;heartbeatTimer;constructor(t){this.sessionDir=t,this.lockPath=x.join(t,Dt),this.legacyLockPath=x.join(t,Et),this.sessionId=x.basename(t)}async acquire(){let t=new Date().toISOString(),e={schemaVersion:1,name:`session:${this.sessionId}`,sessionId:this.sessionId,pid:process.pid,hostname:Q.hostname(),processStartedAt:new Date(Date.now()-Math.floor(process.uptime()*1e3)).toISOString(),version:dt,acquiredAt:t,updatedAt:t,heartbeat:t},r=x.dirname(this.lockPath);await R.promises.mkdir(r,{recursive:!0});let n=await this.findExistingLockPath();if(n){if(!await this.isStalePath(n)){let o=await this.readLockAt(n);throw new Error(`Session ${this.sessionId} is already locked by PID ${o?.pid} on ${o?.hostname}`)}await k(n)}try{await R.promises.writeFile(this.lockPath,JSON.stringify(e,null,2),{flag:"wx",encoding:"utf-8"}),$.add(this.lockPath)}catch(i){if(i.code==="EEXIST"){if(!await this.isStalePath(this.lockPath)){let l=await this.readLockAt(this.lockPath);throw new Error(`Session ${this.sessionId} is already locked by PID ${l?.pid} on ${l?.hostname}`)}await k(this.lockPath);try{await R.promises.writeFile(this.lockPath,JSON.stringify(e,null,2),{flag:"wx",encoding:"utf-8"})}catch(l){throw l.code==="EEXIST"?new Error(`Session ${this.sessionId} lock was acquired by another process during stale recovery`):l}$.add(this.lockPath)}else throw i}}async release(){this.stopHeartbeat(),$.delete(this.lockPath),await k(this.lockPath)}async isLocked(){let t=await this.findExistingLockPath();return t?!await this.isStalePath(t):!1}async isStale(){let t=await this.findExistingLockPath();return t?this.isStalePath(t):!1}async isStalePath(t){let e=await this.readLockAt(t);if(!e)return!1;let r=new Date(e.heartbeat).getTime();return Date.now()-r>bt}startHeartbeat(t=vt){this.heartbeatTimer&&this.stopHeartbeat(),this.heartbeatTimer=setInterval(async()=>{try{await this.updateHeartbeat()}catch(e){let r=e instanceof Error?e.message:String(e);if(e?.code==="ENOENT"){P("SessionLock: Session directory removed, stopping heartbeat"),this.stopHeartbeat();return}P(`SessionLock: Failed to update heartbeat: ${r}`)}},t),this.heartbeatTimer.unref()}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0)}async updateHeartbeat(){let t=await this.readLockAt(this.lockPath);t&&(t.pid!==process.pid||t.hostname!==Q.hostname()||(t.heartbeat=new Date().toISOString(),t.updatedAt=t.heartbeat,await p(this.lockPath,JSON.stringify(t,null,2))))}async readLock(){let t=await this.findExistingLockPath();return t?this.readLockAt(t):null}async readLockAt(t){let e=await u(t);return e?f(e,null):null}async findExistingLockPath(){return await u(this.lockPath)?this.lockPath:await u(this.legacyLockPath)?this.legacyLockPath:null}static async cleanStale(t){let e=await B(t),r=[];for(let n of e){let i=new s(n);if(await i.isStale()){let a=await i.findExistingLockPath();a&&await k(a),r.push(x.basename(n))}}return r}};import*as y from"path";import*as mt from"os";import*as w from"path";function It(s,t){let e=w.resolve(s),r=w.resolve(s,t);return r===e?!0:e===w.parse(e).root?r.startsWith(e):r.startsWith(e+w.sep)}function b(s,t){if(w.isAbsolute(t))return w.resolve(t);if(!It(s,t))throw new Error(`PathSecurity: Path traversal attempt detected: ${t}`);return w.resolve(s,t)}import*as D from"path";import*as Y from"os";var X=1,Rt="recent.json";function N(s=Y.homedir()){return D.join(s,".xeno-agent",Rt)}function J(s){let t=D.normalize(s).replace(/[\\/]+$/,""),e=t.length>0?t:D.parse(D.normalize(s)).root;return process.platform==="win32"?e.toLowerCase():e}async function j(s=Y.homedir()){let t={version:X,entries:{}},e=N(s);if(!L(e))return t;let r=await u(e);if(!r)return t;let n=f(r,null);if(!n||typeof n!="object")return t;let i=n;if(i.version!==X||!i.entries||typeof i.entries!="object")return t;let o={};for(let[a,l]of Object.entries(i.entries)){if(!l||typeof l!="object")continue;let c=l;typeof c.sessionId!="string"||c.sessionId.length===0||typeof c.endedAt=="string"&&(o[a]={sessionId:c.sessionId,endedAt:c.endedAt,role:typeof c.role=="string"?c.role:void 0})}return{version:X,entries:o}}async function Z(s,t={}){let e=await j(t.homeDir),r=J(s),n=e.entries[r];if(n&&!(t.role&&n.role&&n.role!==t.role))return n}async function tt(s,t={}){let e=await j(t.homeDir),r=J(s.cwd);e.entries[r]={sessionId:s.sessionId,role:s.role,endedAt:s.endedAt??new Date().toISOString()};let n=N(t.homeDir);await p(n,JSON.stringify(e,null,2)+`
45
+ `:"";await p(this.transcriptPath,a);let l=this.buildMarkdownDocument(o,"session store");if(await p(this.markdownPath,l),!this.workspaceMirrorDisabled){let c=await this.resolveWorkspaceMarkdownPath();if(c)try{let m=this.buildMarkdownDocument(o,"workspace mirror");await p(c,m)}catch(m){this.workspaceMirrorDisabled=!0,S("Transcript workspace mirror disabled",m)}}}getSequence(){return this.sequence}async initialize(){try{let t=await u(this.transcriptPath);if(!t){this.sequence=0;return}let e=_(t);if(e.length===0){this.sequence=0;return}let r=e[e.length-1];this.sequence=r.sequence+1}catch(t){let e=t instanceof Error?t.message:String(t);S(`Transcript initialization warning: ${e}. Starting with empty transcript.`),this.sequence=0}}async flush(){await this.writeQueue}};import*as O from"path";import{randomUUID as xt}from"crypto";var St={View:"Read",Replace:"Write",GlobTool:"Glob",GrepTool:"Grep",SQLiteAnalyze:"SqliteAnalyze",ReadNotebook:"NotebookRead",NotebookEditCell:"NotebookEdit"};function W(s){return St[s]??s}var I=class{sessionDir;checkpointsDir;autoInterval;lastCheckpointMessageCount=0;constructor(t,e){this.sessionDir=t,this.checkpointsDir=O.join(t,"checkpoints"),this.autoInterval=e?.autoInterval??10}async initialize(){let t=await this.list();t.length>0&&(this.lastCheckpointMessageCount=t[0].messageCount)}async create(t){await E(this.checkpointsDir);let e=xt(),r={id:e,name:t.description,trigger:t.trigger,createdAt:new Date().toISOString(),messageCount:t.messages.length,tokenCount:this.estimateTokens(t.messages)},n={info:r,messages:t.messages},i=O.join(this.checkpointsDir,`${e}.json`);return await p(i,JSON.stringify(n,null,2)),this.lastCheckpointMessageCount=t.messages.length,r}async list(){let t=await ot(this.checkpointsDir,/\.json$/),e=[];for(let r of t){let n=await u(r);if(n){let i=f(n,null);i&&e.push(i.info)}}return e.sort((r,n)=>new Date(n.createdAt).getTime()-new Date(r.createdAt).getTime())}async restore(t){let e=O.join(this.checkpointsDir,`${t}.json`),r;try{r=await u(e)}catch(i){let o=i instanceof Error?i.message:String(i);throw new Error(`Failed to read checkpoint ${t}: ${o}`)}if(!r)throw new Error(`Checkpoint not found: ${t} (path: ${e})`);let n=f(r,null);if(!n)throw new Error(`Invalid checkpoint data for ${t}: JSON parse failed`);if(!n.messages||!Array.isArray(n.messages))throw new Error(`Invalid checkpoint data for ${t}: missing or invalid messages array`);if(!n.info)throw new Error(`Invalid checkpoint data for ${t}: missing info object`);return{messages:n.messages,info:n.info}}shouldAutoCheckpoint(t){return t-this.lastCheckpointMessageCount>=this.autoInterval}static isDangerousOperation(t,e){if(t=W(t),t==="Write")return!0;if(t==="Bash"){let n=e.command?.toLowerCase()||"";return["rm ","del ","git push","git reset","drop ","truncate"].some(o=>n.includes(o))}return!1}async delete(t){let e=O.join(this.checkpointsDir,`${t}.json`);await k(e)}estimateTokens(t){let e=0;for(let r of t)if(typeof r.content=="string")e+=Math.ceil(r.content.length/4);else if(Array.isArray(r.content))for(let n of r.content)"text"in n&&(e+=Math.ceil(n.text.length/4));return e}};import*as x from"path";import*as Q from"os";import*as R from"fs";var K=new Set,ut=!1;function Pt(){for(let s of K)try{s()}catch{}}function pt(s){return K.add(s),!ut&&typeof process<"u"&&typeof process.on=="function"&&(ut=!0,process.on("exit",Pt)),()=>{K.delete(s)}}var dt="0.6.4";var vt=1e4,bt=6e4,Dt="session.lock",Et="lock.json",$=new Set;function Tt(){for(let s of $)try{R.unlinkSync(s)}catch{}$.clear()}pt(Tt);var M=class s{sessionDir;lockPath;legacyLockPath;sessionId;heartbeatTimer;constructor(t){this.sessionDir=t,this.lockPath=x.join(t,Dt),this.legacyLockPath=x.join(t,Et),this.sessionId=x.basename(t)}async acquire(){let t=new Date().toISOString(),e={schemaVersion:1,name:`session:${this.sessionId}`,sessionId:this.sessionId,pid:process.pid,hostname:Q.hostname(),processStartedAt:new Date(Date.now()-Math.floor(process.uptime()*1e3)).toISOString(),version:dt,acquiredAt:t,updatedAt:t,heartbeat:t},r=x.dirname(this.lockPath);await R.promises.mkdir(r,{recursive:!0});let n=await this.findExistingLockPath();if(n){if(!await this.isStalePath(n)){let o=await this.readLockAt(n);throw new Error(`Session ${this.sessionId} is already locked by PID ${o?.pid} on ${o?.hostname}`)}await k(n)}try{await R.promises.writeFile(this.lockPath,JSON.stringify(e,null,2),{flag:"wx",encoding:"utf-8"}),$.add(this.lockPath)}catch(i){if(i.code==="EEXIST"){if(!await this.isStalePath(this.lockPath)){let l=await this.readLockAt(this.lockPath);throw new Error(`Session ${this.sessionId} is already locked by PID ${l?.pid} on ${l?.hostname}`)}await k(this.lockPath);try{await R.promises.writeFile(this.lockPath,JSON.stringify(e,null,2),{flag:"wx",encoding:"utf-8"})}catch(l){throw l.code==="EEXIST"?new Error(`Session ${this.sessionId} lock was acquired by another process during stale recovery`):l}$.add(this.lockPath)}else throw i}}async release(){this.stopHeartbeat(),$.delete(this.lockPath),await k(this.lockPath)}async isLocked(){let t=await this.findExistingLockPath();return t?!await this.isStalePath(t):!1}async isStale(){let t=await this.findExistingLockPath();return t?this.isStalePath(t):!1}async isStalePath(t){let e=await this.readLockAt(t);if(!e)return!1;let r=new Date(e.heartbeat).getTime();return Date.now()-r>bt}startHeartbeat(t=vt){this.heartbeatTimer&&this.stopHeartbeat(),this.heartbeatTimer=setInterval(async()=>{try{await this.updateHeartbeat()}catch(e){let r=e instanceof Error?e.message:String(e);if(e?.code==="ENOENT"){P("SessionLock: Session directory removed, stopping heartbeat"),this.stopHeartbeat();return}P(`SessionLock: Failed to update heartbeat: ${r}`)}},t),this.heartbeatTimer.unref()}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0)}async updateHeartbeat(){let t=await this.readLockAt(this.lockPath);t&&(t.pid!==process.pid||t.hostname!==Q.hostname()||(t.heartbeat=new Date().toISOString(),t.updatedAt=t.heartbeat,await p(this.lockPath,JSON.stringify(t,null,2))))}async readLock(){let t=await this.findExistingLockPath();return t?this.readLockAt(t):null}async readLockAt(t){let e=await u(t);return e?f(e,null):null}async findExistingLockPath(){return await u(this.lockPath)?this.lockPath:await u(this.legacyLockPath)?this.legacyLockPath:null}static async cleanStale(t){let e=await B(t),r=[];for(let n of e){let i=new s(n);if(await i.isStale()){let a=await i.findExistingLockPath();a&&await k(a),r.push(x.basename(n))}}return r}};import*as y from"path";import*as mt from"os";import*as w from"path";function It(s,t){let e=w.resolve(s),r=w.resolve(s,t);return r===e?!0:e===w.parse(e).root?r.startsWith(e):r.startsWith(e+w.sep)}function b(s,t){if(w.isAbsolute(t))return w.resolve(t);if(!It(s,t))throw new Error(`PathSecurity: Path traversal attempt detected: ${t}`);return w.resolve(s,t)}import*as D from"path";import*as Y from"os";var X=1,Rt="recent.json";function N(s=Y.homedir()){return D.join(s,".xeno-agent",Rt)}function J(s){let t=D.normalize(s).replace(/[\\/]+$/,""),e=t.length>0?t:D.parse(D.normalize(s)).root;return process.platform==="win32"?e.toLowerCase():e}async function j(s=Y.homedir()){let t={version:X,entries:{}},e=N(s);if(!L(e))return t;let r=await u(e);if(!r)return t;let n=f(r,null);if(!n||typeof n!="object")return t;let i=n;if(i.version!==X||!i.entries||typeof i.entries!="object")return t;let o={};for(let[a,l]of Object.entries(i.entries)){if(!l||typeof l!="object")continue;let c=l;typeof c.sessionId!="string"||c.sessionId.length===0||typeof c.endedAt=="string"&&(o[a]={sessionId:c.sessionId,endedAt:c.endedAt,role:typeof c.role=="string"?c.role:void 0})}return{version:X,entries:o}}async function Z(s,t={}){let e=await j(t.homeDir),r=J(s),n=e.entries[r];if(n&&!(t.role&&n.role&&n.role!==t.role))return n}async function tt(s,t={}){let e=await j(t.homeDir),r=J(s.cwd);e.entries[r]={sessionId:s.sessionId,role:s.role,endedAt:s.endedAt??new Date().toISOString()};let n=N(t.homeDir);await p(n,JSON.stringify(e,null,2)+`
46
46
  `)}async function Mt(s,t={}){let e=await j(t.homeDir),r=J(s);if(!(r in e.entries))return;delete e.entries[r];let n=N(t.homeDir);await p(n,JSON.stringify(e,null,2)+`
47
47
  `)}async function q(s,t={}){let e=await j(t.homeDir),r=!1;for(let[i,o]of Object.entries(e.entries))o.sessionId===s&&(delete e.entries[i],r=!0);if(!r)return;let n=N(t.homeDir);await p(n,JSON.stringify(e,null,2)+`
48
48
  `)}var C=class{static getSessionsDir(){let t=process.env.XENO_AGENT_HOME?.trim()||y.join(mt.homedir(),".xeno-agent");return y.join(t,"sessions")}static async list(t){let e=this.getSessionsDir(),r=typeof t?.limit=="number"&&Number.isFinite(t.limit)?Math.max(0,Math.floor(t.limit)):void 0;if(r===0)return[];let n=t?.workingDirectory?this.normalizeWorkingDirectory(t.workingDirectory):void 0;if(!L(e))return[];let i=await B(e),o=[];for(let a of i){let l=await this.loadMeta(a);l&&(t?.status&&!t.status.includes(l.status)||t?.role&&l.role!==t.role||n&&this.normalizeWorkingDirectory(l.workingDirectory)!==n||o.push(l))}return o.sort((a,l)=>new Date(l.lastActivity).getTime()-new Date(a.lastActivity).getTime()),r!==void 0?o.slice(0,r):o}static async find(t){let e=this.getSessionsDir(),r=b(e,t);return await this.loadMeta(r)}static async findMostRecent(t){let e=typeof t=="string"?{role:t}:t??{};if(e.workingDirectory){let i=await Z(e.workingDirectory,{...e.role!==void 0?{role:e.role}:{}});if(i){let o=await this.find(i.sessionId);if(o){if(!(e.role&&o.role!==e.role)){if(this.normalizeWorkingDirectory(o.workingDirectory)===this.normalizeWorkingDirectory(e.workingDirectory))return o}}else await q(i.sessionId)}}let n=(await this.list({...e.role!==void 0?{role:e.role}:{},...e.workingDirectory!==void 0?{workingDirectory:e.workingDirectory}:{},limit:1}))[0]??null;if(n&&e.workingDirectory)try{await tt({cwd:n.workingDirectory,sessionId:n.id,role:n.role,endedAt:n.lastActivity})}catch{}return n}static async delete(t){let e=this.getSessionsDir(),r=b(e,t);await at(r),await q(t)}static async purgeWorkingDirectory(t,e){let r=new Set(e?.excludeSessionIds??[]),n=await this.list({workingDirectory:t}),i=[],o=[];for(let a of n){if(r.has(a.id)){o.push(a.id);continue}await this.delete(a.id),await this.deleteWorkspaceMirror(t,a.id),i.push(a.id)}return{deletedIds:i,skippedIds:o}}static async updateMeta(t,e){let r=this.getSessionsDir(),n=b(r,t),i=y.join(n,"meta.json"),o=await u(i);if(!o)throw new Error(`Session not found: ${t}`);let a=f(o,null);if(!a)throw new Error(`Invalid session metadata: ${t}`);let l={...a,...e,updatedAt:new Date().toISOString()};return await p(i,JSON.stringify(l,null,2)),l}static async loadMeta(t){let e=y.join(t,"meta.json"),r=await u(e);if(!r)return null;let n=f(r,null);if(!n)return null;let i=n.formatVersion;return{...n,formatVersion:typeof i=="number"&&Number.isFinite(i)&&i>0?i:1}}static getSessionDir(t){return b(this.getSessionsDir(),t)}static normalizeWorkingDirectory(t){let e=y.normalize(t).replace(/[\\/]+$/,""),r=e.length>0?e:y.parse(y.normalize(t)).root;return process.platform==="win32"?r.toLowerCase():r}static async deleteWorkspaceMirror(t,e){let r=y.join(t,".xeno","sessions",`${e}.md`);await k(r)}};import*as U from"path";var et=class s{sessionDir;_meta;_transcript;_checkpoints;_lock;constructor(t,e,r,n,i){this.sessionDir=t,this._meta=e,this._transcript=r,this._checkpoints=n,this._lock=i}static async create(t){let e=t.role??"default",r=G(e),n=C.getSessionDir(r),i=null,o=null;try{await E(n);let a={id:r,role:e,status:"creating",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString(),lastActivity:new Date().toISOString(),workingDirectory:t.workingDirectory,model:t.model,parentSession:t.parentSession,checkpoints:[],messageCount:0,tokenUsage:{input:0,output:0,total:0},formatVersion:1},l=U.join(n,"meta.json");await p(l,JSON.stringify(a,null,2)),o=new T(n);let c=new I(n);i=new M(n),await i.acquire(),i.startHeartbeat(),await o.append({type:"session_start",data:{sessionId:r,role:e,workingDirectory:t.workingDirectory,model:t.model,formatVersion:1}});let m=new s(n,a,o,c,i);return await m.updateMeta({status:"active"}),m}catch(a){if(i)try{i.stopHeartbeat(),await i.release()}catch(l){P("Error releasing lock during cleanup",l)}throw a}}static async resume(t){let e=C.getSessionDir(t.sessionId),r=null,n=null;try{let i=U.join(e,"meta.json"),o=await u(i);if(!o)throw new Error(`SessionManager: Session not found: ${t.sessionId}`);let a=f(o,null);if(!a)throw new Error(`SessionManager: Invalid session metadata: ${t.sessionId}`);a.formatVersion=gt(a),n=new T(e),await n.initialize();let l=new I(e);if(r=new M(e),await r.acquire(),r.startHeartbeat(),t.fromCheckpoint){let{info:m}=await l.restore(t.fromCheckpoint);a.messageCount=m.messageCount,await n.append({type:"checkpoint",data:{id:t.fromCheckpoint,trigger:"manual",messageCount:m.messageCount}})}let c=new s(e,a,n,l,r);return await c.updateMeta({status:"active",lastActivity:new Date().toISOString()}),c}catch(i){if(r)try{r.stopHeartbeat(),await r.release()}catch(o){P("Error releasing lock during cleanup",o)}throw i}}get meta(){return{...this._meta}}get transcript(){return this._transcript}get checkpoints(){return this._checkpoints}async updateMeta(t){this._meta={...this._meta,...t,updatedAt:new Date().toISOString()};let e=U.join(this.sessionDir,"meta.json"),r=3,n=null;for(let i=0;i<r;i++)try{await p(e,JSON.stringify(this._meta,null,2));return}catch(o){n=o instanceof Error?o:new Error(String(o)),S(`Failed to write session metadata (attempt ${i+1}/${r}): ${n.message}`),i<r-1&&await new Promise(a=>setTimeout(a,Math.pow(2,i)*100))}P(`Failed to write session metadata after ${r} attempts. Session will continue but metadata may be stale.`)}async end(t="completed"){await this._transcript.append({type:"session_end",data:{reason:t==="completed"?"completed":"user_exit",messageCount:this._meta.messageCount,totalTokens:this._meta.tokenUsage.total}}),await this._transcript.flush(),await this.updateMeta({status:t}),this._lock.stopHeartbeat(),await this._lock.release()}async recordUserMessage(t){await this._transcript.append({type:"user_message",data:{role:"user",content:t}}),await this.updateMeta({messageCount:this._meta.messageCount+1,lastActivity:new Date().toISOString()})}async recordAssistantMessage(t,e){await this._transcript.append({type:"assistant_message",data:{role:"assistant",content:t},tokenCount:e}),await this.updateMeta({messageCount:this._meta.messageCount+1,lastActivity:new Date().toISOString()})}async recordTokenUsage(t,e){let r={input:this._meta.tokenUsage.input+t,output:this._meta.tokenUsage.output+e,total:this._meta.tokenUsage.total+t+e};await this.updateMeta({tokenUsage:r})}async recordDelegationSummary(t){await this._transcript.append({type:"delegation_summary",data:t}),await this.updateMeta({lastActivity:new Date().toISOString()})}async updateMessageCount(t){t!==this._meta.messageCount&&await this.updateMeta({messageCount:t,lastActivity:new Date().toISOString()})}};function gt(s){let t=s?.formatVersion;return typeof t=="number"&&Number.isFinite(t)&&t>0?t:1}import{randomUUID as Ct}from"crypto";import{mkdir as z,readFile as rt,readdir as ft,rm as V,stat as At,writeFile as nt}from"fs/promises";import g from"path";var st=class{constructor(t,e){this.sessionDir=t;this.workspaceDir=e;this.restoreRoot=g.join(t,"turn-restores")}sessionDir;workspaceDir;restoreRoot;operationQueue=Promise.resolve();async create(t){let e={id:t.id??Ct(),createdAt:new Date().toISOString(),restoreMessageCount:t.restoreMessageCount,userPrompt:t.userPrompt,mutations:[],unsupportedTools:[]};return this.enqueue(async()=>{let r=this.getRestoreDir(e.id);return await z(g.join(r,"backups"),{recursive:!0}),await this.savePoint(e),e})}async recordToolExecution(t,e,r){if(e=W(e),e==="Write"||e==="Edit"){let n=typeof r.file_path=="string"?r.file_path:"";if(!n)return;await this.captureFileMutation(t,n);return}e==="Bash"&&await this.markUnsupportedTool(t,"Bash")}async restoreAtOrAfter(t){return this.enqueue(async()=>{let e=await this.inspectAtOrAfterInternal(t);if(!e.hadRestorePoints)return{...e,restoredFiles:0,removedFiles:0};let r=new Map;for(let o of e.points)for(let a of o.mutations){if(!a.existedBefore||!a.backupFile)continue;let l=this.getBackupPath(o.id,a.backupFile);r.set(l,await rt(l,"utf8"))}let n=0,i=0;for(let o of[...e.points].reverse())for(let a of[...o.mutations].reverse()){let l=g.join(this.workspaceDir,a.relativePath);if(a.existedBefore&&a.backupFile){let c=this.getBackupPath(o.id,a.backupFile);await z(g.dirname(l),{recursive:!0}),await nt(l,r.get(c)??"","utf8"),n+=1;continue}await V(l,{recursive:!0,force:!0}),await this.pruneEmptyParentDirs(g.dirname(l)),i+=1}for(let o of e.points)await V(this.getRestoreDir(o.id),{recursive:!0,force:!0});return{...e,restoredFiles:n,removedFiles:i}})}async deleteAtOrAfter(t){await this.enqueue(async()=>{let e=await this.listPointsAtOrAfter(t);for(let r of e)await V(this.getRestoreDir(r.id),{recursive:!0,force:!0})})}async inspectAtOrAfter(t){return this.enqueue(async()=>this.inspectAtOrAfterInternal(t))}async findByRestoreMessageCount(t){return(await this.inspectAtOrAfter(t)).points.filter(n=>n.restoreMessageCount===t).at(-1)??null}async captureFileMutation(t,e){await this.enqueue(async()=>{let r=await this.loadPoint(t),n;try{n=b(this.workspaceDir,e)}catch{return}let i=g.relative(this.workspaceDir,n);if(!i||r.mutations.some(c=>c.relativePath===i))return;try{if(!(await At(n)).isFile()){r.mutations.push({relativePath:i,existedBefore:!1}),await this.savePoint(r);return}}catch(c){if(c.code==="ENOENT"){r.mutations.push({relativePath:i,existedBefore:!1}),await this.savePoint(r);return}throw c}let o=`${r.mutations.length+1}.txt`,a=this.getBackupPath(t,o),l=await rt(n,"utf8");await z(g.dirname(a),{recursive:!0}),await nt(a,l,"utf8"),r.mutations.push({relativePath:i,existedBefore:!0,backupFile:o}),await this.savePoint(r)})}async markUnsupportedTool(t,e){await this.enqueue(async()=>{let r=await this.loadPoint(t);r.unsupportedTools.includes(e)||(r.unsupportedTools.push(e),await this.savePoint(r))})}async inspectAtOrAfterInternal(t){let e=await this.listPointsAtOrAfter(t),r=Array.from(new Set(e.flatMap(n=>n.unsupportedTools)));return{points:e,hadRestorePoints:e.length>0,exactWorkspaceRestore:e.length>0&&r.length===0,unsupportedTools:r}}async listPointsAtOrAfter(t){try{let e=await ft(this.restoreRoot,{withFileTypes:!0}),r=[];for(let n of e)if(n.isDirectory())try{let i=await this.loadPoint(n.name);i.restoreMessageCount>=t&&r.push(i)}catch{continue}return r.sort((n,i)=>n.createdAt.localeCompare(i.createdAt)),r}catch{return[]}}async loadPoint(t){let e=g.join(this.getRestoreDir(t),"meta.json"),r=await rt(e,"utf8"),n=JSON.parse(r);if(!n||typeof n.id!="string"||typeof n.restoreMessageCount!="number")throw new Error(`Invalid restore point metadata: ${t}`);return n}async savePoint(t){let e=this.getRestoreDir(t.id);await z(e,{recursive:!0}),await nt(g.join(e,"meta.json"),JSON.stringify(t,null,2),"utf8")}async pruneEmptyParentDirs(t){let e=g.resolve(this.workspaceDir),r=g.resolve(t);for(;r.startsWith(`${e}${g.sep}`)&&r!==e;){let n;try{n=await ft(r)}catch(i){if(i.code==="ENOENT"){r=g.dirname(r);continue}throw i}if(n.length>0)break;await V(r,{recursive:!1,force:!0}),r=g.dirname(r)}}getRestoreDir(t){return g.join(this.restoreRoot,t)}getBackupPath(t,e){return g.join(this.getRestoreDir(t),"backups",e)}enqueue(t){let e=this.operationQueue.then(t,t);return this.operationQueue=e.then(()=>{},()=>{}),e}};export{I as CheckpointManager,M as SessionLock,et as SessionManager,C as SessionRegistry,T as TranscriptWriter,st as TurnRestoreManager,Mt as forgetRecentSession,q as forgetRecentSessionById,G as generateSessionId,N as getRecentSessionsIndexPath,wt as isValidSessionId,j as loadRecentSessionsIndex,Z as lookupRecentSession,J as normalizeWorkingDirectory,it as parseSessionId,gt as readSessionFormatVersion,tt as recordRecentSession};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xeno-corporation/xeno-agent-sdk",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "XENO Agent SDK built from the same engine as XENO CODE",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -62,6 +62,10 @@
62
62
  "access": "public"
63
63
  },
64
64
  "homepage": "https://xenostudio.ai",
65
+ "repository": {
66
+ "type": "git",
67
+ "url": "git+https://github.com/XENO-CORPORATION/xeno-agent-sdk.git"
68
+ },
65
69
  "bugs": {
66
70
  "url": "https://xenostudio.ai/contact"
67
71
  },