@gigabuddy/agent 0.1.0 → 0.1.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/agent-cli.js +2 -2
- package/package.json +1 -1
package/agent-cli.js
CHANGED
|
@@ -229,12 +229,12 @@ ${l}`:l}}}function Nz(t){return t instanceof Map?t:t?new Map(Object.entries(t)):
|
|
|
229
229
|
`).trim()}function e2(t){return!t.content||typeof t.content=="string"||!Array.isArray(t.content)?"":t.content.map(e=>e.text??"").join("")}function V_(t){if(!t||!Array.isArray(t))return[];let e=[];for(let r=0;r<t.length;r++){let i=t[r];if(!i||i.type!=="heading")continue;let n=i.props?.level??2,o=e2(i);e.push({heading:o,level:n,startIndex:r,endIndex:t.length})}for(let r=0;r<e.length;r++){let i=e[r];for(let n=r+1;n<e.length;n++)if(e[n].level<=i.level){i.endIndex=e[n].startIndex;break}}return e}function H_(t,e){let r=V_(t),i=V_(e),n=new Map;for(let l of r){let u=t.slice(l.startIndex,l.endIndex);n.set(l.heading,q_(u))}let o=new Map;for(let l of i){let u=e.slice(l.startIndex,l.endIndex);o.set(l.heading,q_(u))}let s=[],a=[],c=[];for(let[l,u]of o){let d=n.get(l);d===void 0?s.push(l):d!==u&&c.push(l)}for(let l of n.keys())o.has(l)||a.push(l);return{added:s,removed:a,changed:c}}var B_=50,t2=300,r2=25e3,n2=5*6e4,i2=500,o2=4e3,Cf=class{constructor(e,r,i){this.state=e;this.sessionId=r;this.pageChecker=i?.pageChecker??null,this.workspaceSyncer=i?.workspaceSyncer??null,this.profileSyncer=i?.profileSyncer??null,this.messageFetcher=i?.messageFetcher??null,this.changedFetcher=i?.changedFetcher??null}seq=0;events=[];previousPeers=new Map;debounceTimer=null;unsubscribe=null;outboxAbort=null;heartbeatTimer=null;mentionWatchTimer=null;placeEventUnsub=null;connectionUnsub=null;contentDebounceTimers=new Map;hasConnected=!1;lastOutboxFile=null;pageChecker=null;messageFetcher=null;changedFetcher=null;lastContentSyncTs=null;workspaceSyncer=null;lastWorkspaceSyncTs=0;profileSyncer=null;lastProfileSyncTs=0;lastMentionCursor=null;lastPersistedCursor=null;seenMessageIds=new Set;persistTimer=null;lastContextPct=null;lastContextTokens=null;lastContextWindowK=null;lastShouldHandoff=!1;lastRssMb=null;lastHostPressure=null;lastCpuCores=null;lastCpuPressure=null;lastCpuTicks=null;lastCpuSampleAt=null;lastLocation=null;lastLocationCwd=null;selfPid=null;selfPidResolved=!1;get inboxPath(){return W_(Je(this.sessionId),"inbox.json")}get sessionStatePath(){return W_(Je(this.sessionId),"cursor.json")}async start(){await Zr(this.sessionId);let e=this.state.awarenessManager,r=this.state.placeId;!e||!r||(await this.loadSessionState(),this.state.currentActivity&&e.updateTopicState(r,{activityId:this.state.currentActivity.activityId}),this.snapshotPeers(e,r),await this.writeInbox(),sr(this.state),this.unsubscribe=e.onTopicUpdate(r,()=>{this.onPeerUpdate(e,r)}),this.watchOutbox(e,r),this.heartbeatTimer=setInterval(async()=>{if(!e.connected){if(await e.ensureConnected())try{await e.subscribe(r),e.updateTopicState(r,{displayName:this.state.agentMeta?.displayName,status:"active"}),console.error("[gigabuddy-inbox] Heartbeat restored dead connection")}catch{}return}await this.refreshSessionName(e,r),await this.refreshContext(e,r),await this.refreshResources(e,r),await this.refreshLocation(e,r),sr(this.state)},r2),this.placeEventUnsub=e.onPlaceEvent(i=>{this.onContentChanged(r,i).catch(n=>console.error("[gigabuddy-inbox] content_changed handler error:",n)),this.onActivityChanged(i),this.onMessageCreated(i),this.onAskCreated(i)}),this.lastContentSyncTs=new Date().toISOString(),this.connectionUnsub=e.onConnectionChange(i=>{if(!i)return;if(!this.hasConnected){this.hasConnected=!0;return}let n=this.lastContentSyncTs??new Date(Date.now()-5*6e4).toISOString();this.lastContentSyncTs=new Date().toISOString(),this.catchUpChangedContent(r,n).catch(o=>console.error("[gigabuddy-inbox] reconnect catch-up error:",o)),this.checkMentions(r).catch(o=>console.error("[gigabuddy-inbox] reconnect mention catch-up error:",o))}),this.messageFetcher&&(this.lastMentionCursor||(this.lastMentionCursor=this.state.lastMessageCursor),this.checkMentions(r).catch(i=>console.error("[gigabuddy-inbox] Mention bootstrap error:",i)),this.mentionWatchTimer=setInterval(()=>{this.checkMentions(r).catch(i=>console.error("[gigabuddy-inbox] Mention check error:",i))},n2)))}stop(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.debounceTimer&&(clearTimeout(this.debounceTimer),this.debounceTimer=null),this.outboxAbort&&(this.outboxAbort.abort(),this.outboxAbort=null),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.placeEventUnsub&&(this.placeEventUnsub(),this.placeEventUnsub=null);for(let e of this.contentDebounceTimers.values())clearTimeout(e);this.contentDebounceTimers.clear(),this.connectionUnsub&&(this.connectionUnsub(),this.connectionUnsub=null),this.mentionWatchTimer&&(clearInterval(this.mentionWatchTimer),this.mentionWatchTimer=null),this.persistTimer&&(clearTimeout(this.persistTimer),this.persistTimer=null),this.persistSessionState().catch(()=>{})}addEvent(e){e.type==="page_updated"&&e.pageId&&(this.events=this.events.filter(r=>!(r.type==="page_updated"&&r.pageId===e.pageId))),this.events.push({...e,ts:new Date().toISOString()}),this.events.length>B_&&(this.events=this.events.slice(-B_)),this.scheduleWrite()}notePosition(){this.schedulePersist()}noteSelfChanged(){this.scheduleWrite(),this.schedulePersist()}watchOutbox(e,r){let i=W_(Je(this.sessionId),"outbox.json");this.outboxAbort=new AbortController;let n=null,o=async()=>{try{let a=await Dz(i,"utf-8"),c=JSON.parse(a);if(c.ts&&c.ts!==n){n=c.ts;let l={lastActiveAt:c.ts};c.intent&&(l.action={label:c.intent});let u=c.recentFiles?.length?c.recentFiles:c.file?[c.file]:null;u&&JSON.stringify(u)!==JSON.stringify(this.lastOutboxFile?[this.lastOutboxFile]:[])&&(this.lastOutboxFile=u[0]??null,l.focus={kind:"files",ids:u}),c.owner&&(l.owner=c.owner),c.repo&&(l.repo=c.repo),c.branch&&(l.branch=c.branch),e.updateTopicState(r,l);let d=Date.now();if(this.workspaceSyncer&&d-this.lastWorkspaceSyncTs>1e4){this.lastWorkspaceSyncTs=d;let p={last_active_at:c.ts,status:"active"};c.intent&&(p.intent=c.intent),c.owner&&(p.owner=c.owner),c.repo&&(p.repo=c.repo),c.branch&&(p.branch=c.branch),c.recentFiles&&(p.recent_files=c.recentFiles),c.editedFiles&&(p.edited_files=c.editedFiles),c.uncommittedFiles&&(p.uncommitted_files=c.uncommittedFiles),c.gitStats&&(p.git_stats=c.gitStats),c.activeTask&&(p.active_task=c.activeTask),c.taskProgress&&(p.task_progress=c.taskProgress);let f=this.state.currentActivity?.activityId;f&&(p.activity_id=f),this.lastContextPct!=null&&(p.context_pct=this.lastContextPct);let m=this.state.agentMeta?.claudeSessionId,h=m?await pc(m):null;h&&(p.session_name=h),this.workspaceSyncer(p).catch(y=>console.error("[gigabuddy-inbox] Workspace sync error:",y))}if(this.profileSyncer&&d-this.lastProfileSyncTs>3e5){this.lastProfileSyncTs=d;let p=this.state.currentActivity?.label??c.activeTask??c.intent,f={lastDoing:{...p&&{label:p},...this.state.currentActivity?.activityId&&{activityId:this.state.currentActivity.activityId},...r&&{placeId:r},at:c.ts}};c.branch&&(f.branch=c.branch),this.lastContextPct!=null&&(f.metrics={contextPct:this.lastContextPct}),this.profileSyncer(f).catch(m=>console.error("[gigabuddy-inbox] Profile sync error:",m))}}}catch{}},s=setInterval(()=>{if(this.outboxAbort?.signal.aborted){clearInterval(s);return}o()},500);this.outboxAbort.signal.addEventListener("abort",()=>{clearInterval(s)})}onPeerUpdate(e,r){let i=this.buildPeerMap(e,r),n=this.getMyFocus(e,r);if(n.size>0){for(let[o,s]of i)if(s.focus){let a=s.focus.filter(c=>n.has(c));if(a.length>0){let c;for(let u=this.events.length-1;u>=0;u--){let d=this.events[u];if(d&&d.type==="conflict"&&d.peer===o){c=d;break}}c?.files&&JSON.stringify(c.files.sort())===JSON.stringify(a.sort())||this.addEvent({type:"conflict",peer:o,files:a})}}}this.previousPeers=i,this.scheduleWrite()}snapshotPeers(e,r){this.previousPeers=this.buildPeerMap(e,r)}buildPeerMap(e,r){let i=this.state.agentMeta?.displayName,n=new Map;for(let o of e.getTopicPeers(r)){let s=o.state,a=s.displayName??"Unknown";a===i||a==="Unknown"||a.startsWith("user:")||a.startsWith("agent:")||n.set(a,{displayName:a,owner:s.owner??null,status:s.status??"unknown",action:s.action?.label??null,focus:s.focus?.ids??null,activityId:s.activityId??null,lastActiveAt:s.lastActiveAt??null,repo:s.repo??null,branch:s.branch??null,worktreeId:s.worktreeId??null})}return n}myWorktreeId(){let e=this.state.placeId,r=this.state.awarenessManager;return!e||!r?null:r.topics?.get(e)?.localState?.worktreeId??null}getMyFocus(e,r){let o=e.topics?.get(r)?.localState?.focus;return new Set(o?.ids??[])}onActivityChanged(e){if(e.type!=="activity_changed"||e.change!=="attachment")return;let r=e.activityId;if(!r||!this.state.activeActivities.has(r))return;let i=e.actorId;if(i&&this.state.agentId&&i===this.state.agentId)return;let n=e.memberLabel?.trim(),o=e.memberKind??"item";this.addEvent({type:"attachment",peer:i??"someone",detail:n?`"${n}" (${o})`:`a ${o}`})}async onContentChanged(e,r){if(r.type!=="content_changed")return;let i=r.instanceId;!i||!this.state.watchedPages.has(i)||(r.ts&&(!this.lastContentSyncTs||r.ts>this.lastContentSyncTs)&&(this.lastContentSyncTs=r.ts),this.scheduleContentCheck(e,i))}scheduleContentCheck(e,r){let i=this.contentDebounceTimers.get(r);i&&clearTimeout(i);let n=setTimeout(()=>{this.contentDebounceTimers.delete(r),this.checkSingleWatchedPage(e,r).catch(o=>console.error("[gigabuddy-inbox] content check error:",o))},o2);this.contentDebounceTimers.set(r,n)}async checkSingleWatchedPage(e,r){if(!this.pageChecker)return;let i=this.state.watchedPages.get(r);if(!i)return;let n=this.state.agentId;try{let o=await this.pageChecker(e,r);if(!o)return;let{updatedAt:s,lastEditedBy:a}=o;if(!s||s===i.lastKnownUpdatedAt)return;if(a===n){i.lastKnownUpdatedAt=s,o.document&&(i.lastKnownDocument=o.document);return}let c="";if(i.lastKnownDocument&&o.document){let l=H_(i.lastKnownDocument,o.document),u=[];l.changed.length&&u.push(`changed: ${l.changed.join(", ")}`),l.added.length&&u.push(`added: ${l.added.join(", ")}`),l.removed.length&&u.push(`removed: ${l.removed.join(", ")}`),u.length&&(c=` (${u.join("; ")})`)}i.lastKnownUpdatedAt=s,o.document&&(i.lastKnownDocument=o.document),this.addEvent({type:"page_updated",peer:a??"someone",detail:`${i.title}${c}`,pageId:r,pageTitle:i.title})}catch{}}async catchUpChangedContent(e,r){if(!this.changedFetcher||this.state.watchedPages.size===0)return;let i;try{i=await this.changedFetcher(e,r)}catch{return}if(!(!i||i.length===0))for(let n of i)this.state.watchedPages.has(n.instanceId)&&await this.checkSingleWatchedPage(e,n.instanceId)}onMessageCreated(e){if(e.type!=="message_created")return;let r=e.message;r?.id&&this.processIncomingMessages([{id:r.id,content:Lr(r.content),senderName:r.senderName,senderCanonicalId:r.senderCanonicalId,createdAt:r.createdAt??new Date().toISOString(),parentMessageId:r.parentMessageId??void 0,mentionTargets:r.mentionTargets}])}onAskCreated(e){if(e.type!=="ask_created")return;let r=this.state.agentId;if(!r||e.to!==r)return;let i=typeof e.askId=="string"?e.askId:void 0;if(!i)return;let n=typeof e.title=="string"&&e.title?e.title:"(untitled ask)",o=typeof e.urgency=="string"&&e.urgency?` [${e.urgency}]`:"",s=typeof e.discussionActivityId=="string"?e.discussionActivityId:void 0,a=e.target,c=a?.id?` \xB7 about ${a.label?`"${a.label}" `:""}${a.id}`:"";this.addEvent({type:"ask",peer:typeof e.raisedByName=="string"&&e.raisedByName?e.raisedByName:"someone",detail:`${n}${o}${c} \u2014 answer with answer("${i}")`,threadId:s})}async checkMentions(e){if(!this.messageFetcher||!this.state.agentMeta?.displayName)return;let r=this.lastMentionCursor??void 0,i=await this.messageFetcher(e,r);!i||i.length===0||(this.lastMentionCursor=i[i.length-1].id,this.schedulePersist(),this.processIncomingMessages(i))}processIncomingMessages(e){let r=this.state.agentMeta?.displayName,i=this.state.agentId;if(!r)return;let n=r.toLowerCase();for(let o of e){if(this.seenMessageIds.has(o.id))continue;if(this.seenMessageIds.add(o.id),this.seenMessageIds.size>i2){let u=this.seenMessageIds.values().next().value;u!==void 0&&this.seenMessageIds.delete(u)}if(o.senderCanonicalId===i)continue;let s=Lr(o.content),a=s.toLowerCase(),c=i!=null&&(o.mentionTargets?.includes(i)??!1)||a.includes(n)||a.includes(`@${n}`),l=o.parentMessageId&&this.state.subscribedThreads.has(o.parentMessageId);if(c){let u=s.length>120?s.slice(0,120)+"...":s;this.addEvent({type:"mention",peer:o.senderName??"someone",detail:u,threadId:o.parentMessageId}),o.parentMessageId&&this.state.subscribeToThread(o.parentMessageId)}else if(l){let u=s.length>120?s.slice(0,120)+"...":s;this.addEvent({type:"thread_reply",peer:o.senderName??"someone",detail:u,threadId:o.parentMessageId})}}}async loadSessionState(){try{let e=await Dz(this.sessionStatePath,"utf-8"),r=JSON.parse(e);if(r.lastMentionCursor&&(this.lastMentionCursor=r.lastMentionCursor,this.lastPersistedCursor=r.lastMentionCursor),r.subscribedThreads?.length)for(let i of r.subscribedThreads)this.state.subscribedThreads.add(i);if(r.readCursors)for(let[i,n]of Object.entries(r.readCursors))n&&this.state.readCursors.set(i,n);if(r.currentActivity&&!this.state.currentActivity&&this.state.trackActivity(r.currentActivity),r.officeHours?.length){let i=Date.now();for(let n of r.officeHours)n.role==="origin"&&n.until&&Date.parse(n.until)<=i||this.state.officeHours.has(n.pageId)||this.state.officeHours.set(n.pageId,n)}console.error(`[gigabuddy-inbox] Restored session state: cursor=${r.lastMentionCursor}, threads=${r.subscribedThreads?.length??0}, readCursors=${Object.keys(r.readCursors??{}).length}, activity=${r.currentActivity?.activityId??"none"}`)}catch{}}async persistSessionState(){let e={lastMentionCursor:this.lastMentionCursor,subscribedThreads:Array.from(this.state.subscribedThreads),readCursors:Object.fromEntries(this.state.readCursors),currentActivity:this.state.currentActivity,officeHours:Array.from(this.state.officeHours.values()),savedAt:new Date().toISOString()},r=this.sessionStatePath+".tmp";await jz(r,JSON.stringify(e,null,2)),await Uz(r,this.sessionStatePath)}schedulePersist(){this.lastMentionCursor===this.lastPersistedCursor&&this.persistTimer||this.persistTimer||(this.persistTimer=setTimeout(()=>{this.persistTimer=null,this.lastPersistedCursor=this.lastMentionCursor,this.persistSessionState().catch(e=>console.error("[gigabuddy-inbox] Failed to persist session state:",e))},5e3))}scheduleWrite(){this.debounceTimer||(this.debounceTimer=setTimeout(()=>{this.debounceTimer=null,this.writeInbox().catch(e=>{console.error("[gigabuddy-inbox] Failed to write inbox:",e)})},t2))}async refreshSessionName(e,r){let i=this.state.agentMeta;if(!i?.claudeSessionId)return;let n=await pc(i.claudeSessionId);n&&n!==i.sessionName&&(i.sessionName=n,e.updateTopicState(r,{sessionName:n}),this.scheduleWrite())}async refreshLocation(e,r){let i=await CP(this.state.agentMeta?.claudeSessionId);if(!i||i===this.lastLocationCwd)return;this.lastLocationCwd=i;let n=await kf(i);yz(this.lastLocation,n)&&(this.lastLocation=n,e.updateTopicState(r,{repo:n.repo,branch:n.branch,worktree:n.worktree,worktreeId:n.worktreeId,isolated:n.isolated}),this.scheduleWrite())}async refreshContext(e,r){let i=await Fr(this.state.agentMeta?.claudeSessionId);if(!i)return;let n=Math.round(i.usedTokens/1e3),o=i.windowTokens==null?null:Math.round(i.windowTokens/1e3),s=i.pct==null?null:Math.round(i.pct);n===this.lastContextTokens&&o===this.lastContextWindowK&&s===this.lastContextPct&&i.shouldHandoff===this.lastShouldHandoff||(this.lastContextTokens=n,this.lastContextWindowK=o,this.lastContextPct=s,this.lastShouldHandoff=i.shouldHandoff,e.updateTopicState(r,{contextTokensK:n,contextWindowK:o,contextPct:s,shouldHandoff:i.shouldHandoff}),this.scheduleWrite())}async refreshResources(e,r){this.selfPidResolved||(this.selfPidResolved=!0,this.selfPid=(await Vo().catch(()=>null))?.claudePid??null);let[i,n,o]=await Promise.all([this.selfPid!=null?$_(this.selfPid):Promise.resolve(null),Ho(),this.selfPid!=null?hf(this.selfPid):Promise.resolve(null)]),s=i==null?null:Math.round(i/25)*25,a=n?.pressure??null,c=n?.cpuPressure??null,l=Date.now(),u=null;if(o!=null&&this.lastCpuTicks!=null&&this.lastCpuSampleAt!=null){let p=(l-this.lastCpuSampleAt)/1e3;p>0&&(u=Math.max(0,Math.round((o-this.lastCpuTicks)/MP/p*10)/10))}if(o!=null&&(this.lastCpuTicks=o,this.lastCpuSampleAt=l),s===this.lastRssMb&&a===this.lastHostPressure&&c===this.lastCpuPressure&&u===this.lastCpuCores)return;this.lastRssMb=s,this.lastHostPressure=a,this.lastCpuPressure=c,this.lastCpuCores=u;let d={};s!=null&&(d.rssMb=s),a!=null&&(d.hostPressure=a),n?.memPct!=null&&(d.hostMemPct=n.memPct),u!=null&&(d.cpuCores=u),c!=null&&(d.hostCpuPressure=c),Object.keys(d).length!==0&&(e.updateTopicState(r,d),this.scheduleWrite())}async writeInbox(){this.seq++;let e=this.state.placeId;if(!e)return;let r={seq:this.seq,ts:new Date().toISOString(),self:{displayName:this.state.agentMeta?.displayName??"Unknown",agentId:this.state.agentId,placeId:e,activityId:this.state.currentActivity?.activityId??null,activityLabel:this.state.currentActivity?.label??null,sessionId:this.sessionId,claudeSessionId:this.state.agentMeta?.claudeSessionId??null,sessionName:this.state.agentMeta?.sessionName??null,contextTokensK:this.lastContextTokens,contextWindowK:this.lastContextWindowK,contextPct:this.lastContextPct,shouldHandoff:this.lastShouldHandoff,worktreeId:this.myWorktreeId(),officeHours:Array.from(this.state.officeHours.values())},peers:Array.from(this.previousPeers.values()),events:this.events.slice(-B_),...this.state.houseRuleHeadlines?.length?{houseRules:this.state.houseRuleHeadlines}:{}},i=this.inboxPath+".tmp";await jz(i,JSON.stringify(r,null,2)),await Uz(i,this.inboxPath);let n=[...this.events].reverse().find(o=>o.type==="conflict");this.state.statuslineRenderer?.onInbox({displayName:r.self.displayName,placeName:this.state.agentMeta?.placeName??null,activityLabel:r.self.activityLabel,worktreeId:r.self.worktreeId,officeHours:r.self.officeHours,peers:r.peers.map(o=>({displayName:o.displayName,owner:o.owner,worktreeId:o.worktreeId})),conflictFile:n?.files?.[0]??null,messageCount:this.events.filter(o=>o.type==="mention"||o.type==="thread_reply").length})}};import{randomUUID as s2}from"node:crypto";import{mkdir as a2,readFile as Lz,writeFile as c2}from"node:fs/promises";import{homedir as l2}from"node:os";import{join as Zz}from"node:path";var Fz=Zz(l2(),".gigabuddy"),J_=Zz(Fz,"machine-id"),pi=null;async function G_(){if(pi)return pi;try{let t=(await Lz(J_,"utf-8")).trim();if(t)return pi=t,pi}catch{}try{await a2(Fz,{recursive:!0}),await c2(J_,`${s2()}
|
|
230
230
|
`,{flag:"wx"})}catch{}try{pi=(await Lz(J_,"utf-8")).trim()||null}catch{pi=null}return pi}function qz(t,e=Date.now()){let r=Date.parse(t)-e,i=Math.round(Math.abs(r)/6e4),n=i<1?"<1 min":i<90?`${i} min`:`~${Math.round(i/60)}h`;return r>=0?`~${n} left`:`${n} ago`}function u2(t){if(typeof t=="number")return Number.isFinite(t)?t:null;if(typeof t=="string"){let r=Date.parse(t);return Number.isNaN(r)?null:r}let e=t;return e&&typeof e._seconds=="number"?e._seconds*1e3:e&&typeof e.seconds=="number"?e.seconds*1e3:null}function wc(t,e=Date.now()){let r=u2(t);if(r===null)return"";let i=Math.max(0,Math.round((e-r)/1e3));if(i<45)return"just now";let n=Math.round(i/60);if(n<90)return`${Math.max(1,n)} min ago`;let o=Math.round(n/60);return o<36?`${o}h ago`:`${Math.round(o/24)} days ago`}function Vz(t,e){let r={get(i,n,o){if(n!=="updateTopicState"){let s=Reflect.get(i,n,o);return typeof s=="function"?s.bind(i):s}return(s,a)=>{i.updateTopicState(s,a);let c=e.getSponsorTopic(),l=e.getPlaceId();!c||!l||s!==l||i.updateTopicState(c,{...e.getLocation(),...a})}}};return new Proxy(t,r)}async function Hz(t,e,r){let i=await t.claimWork(e,r,{from:"open",to:"active"}).catch(()=>null);i&&!i.won&&(i.status==="stalled"||i.status==="parked")&&await t.claimWork(e,r,{from:i.status,to:"active"}).catch(()=>{})}async function K_(t,e,r){await t.claimWork(e,r,{from:"active",to:"open"}).catch(()=>{})}async function d2(t,e,r){let i=await t.getActivity(e,r).catch(()=>null);for(let n of i?.attachments??[]){if(n.kind!=="content")continue;let o=await t.getPlaceContent(e,n.id).catch(()=>null),s=o?.instance??o;if(s?.data?.handedOverAt)return{id:s.id??n.id,handedOverBy:s.data.handedOverBy??null}}return null}async function Rf(t,e,r){let i=await t.getActivity(e,r).catch(()=>null),n={pageId:null,title:null,handover:null,workItemId:null,workItemStatus:null,originActorId:null};for(let o of i?.attachments??[]){if(o.kind!=="page"&&o.kind!=="content")continue;let s=await t.getPlaceContent(e,o.id).catch(()=>null),a=s?.instance??s;if(a?.data){if(o.kind==="page"&&a.data.handover&&!n.pageId){n.pageId=a.id??o.id,n.title=a.data.title??null,n.handover=a.data.handover;let c=n.handover.origin??{};n.originActorId=c.actorId??n.originActorId}else o.kind==="content"&&a.data.handedOverAt&&!n.workItemId&&(n.workItemId=a.id??o.id,n.workItemStatus=a.data.status??null,n.originActorId??=a.data.handedOverBy??null);if(n.pageId&&n.workItemId)break}}return n.pageId||n.workItemId?n:null}async function Wz(t,e,r,i){let n=await d2(t,e,r).catch(()=>null);!n||i!=null&&n.handedOverBy===i||await K_(t,e,n.id)}var Bz="VnkEV4zbGztvjGknQwt-w";function f2(t){let e=t.sessionId??(t.claudeSessionId?`cc_${t.claudeSessionId}`:null);return e===null?{sessionId:`orient_${process.pid}`,orientOnly:!0}:{sessionId:e,orientOnly:!1}}function m2(t,e,r){if(t.some(s=>s.placeId===e.id))return null;let i=r.find(s=>s.id===e.tenancyId),n=`"${e.name}" (${e.id}) in club "${i?.name??e.tenancyId??"unknown"}"`+(e.visibility==="public"?" \u2014 a PUBLIC room":"");return`Not connecting yet: ${t.length>0?`This repo's sessions have used: ${t.map(s=>`"${s.placeName??s.placeId}"`).join(", ")} \u2014 never ${n}.`:`This repo has no sanctioned rooms yet; the first one deserves a deliberate choice \u2014 you asked for ${n}.`}
|
|
231
231
|
|
|
232
|
-
If the user really wants this session in that room, call connect again with confirm: true \u2014 it will be remembered for this repo and not asked again. Check with them first: everything this session posts will land there.`}var Jz="sanctioned-places.json";async function Gz(){try{let t=await Ef(qr(Rt(),Jz),"utf-8"),e=JSON.parse(t);if(Array.isArray(e.places))return e.places.filter(r=>typeof r.placeId=="string")}catch{}try{let t=await Ef(qr(Rt(),"connection.json"),"utf-8"),e=JSON.parse(t);if(e.placeId)return[{placeId:e.placeId,placeName:e.placeName,tenancyId:e.tenancyId}]}catch{}return[]}async function h2(t){let e=(await Gz()).filter(r=>r.placeId!==t.placeId);e.push({...t,sanctionedAt:new Date().toISOString()}),await g_(),await kc(qr(Rt(),Jz),JSON.stringify({places:e},null,2))}async function g2(t){try{let e=await Ef(qr(Je(t),"session.json"),"utf-8");return JSON.parse(e)}catch{return null}}async function $c(t){await Zr(t.sessionId),await kc(qr(Je(t.sessionId),"session.json"),JSON.stringify(t,null,2))}async function y2(t,e){try{let r=await Ef(qr(Je(t),"ws.json"),"utf-8"),i=JSON.parse(r);return i.placeId===e&&i.instanceId?i.instanceId:null}catch{return null}}async function v2(t,e,r){await Zr(t),await kc(qr(Je(t),"ws.json"),JSON.stringify({placeId:e,instanceId:r}))}function b2(t){try{return JSON.parse(atob(t.split(".")[1])).actingAs?.sub??null}catch{return null}}function _2(t){try{return JSON.parse(atob(t.split(".")[1])).principalType==="agent"}catch{return!1}}function w2(t){try{return JSON.parse(atob(t.split(".")[1])).sub??null}catch{return null}}function $2(t,e){return{...t.tenancyId?{tenancyId:t.tenancyId,installationId:t.tenancyId}:{},placeId:e}}function k2(t,e){let r=e.map(c=>c.state),i=c=>r.filter(l=>l.activityId===c).map(l=>l.displayName??"Unknown"),n=c=>c.updatedAt??c.createdAt??"",o=(c,l)=>({id:c.id,label:c.label,peerName:l?i(c.id).join(", "):void 0,updatedAgo:n(c)?wc(n(c)):void 0}),s=t.filter(c=>i(c.id).length>0),a=t.filter(c=>i(c.id).length===0&&n(c)).sort((c,l)=>n(l).localeCompare(n(c)));return[...s.slice(0,10).map(c=>o(c,!0)),...a.map(c=>o(c,!1))].slice(0,10)}async function X_(t,e,r,i){let n=t.sessionId?{sessionId:t.sessionId,hostSessionId:t.claudeSessionId}:t.claudeSessionId?{sessionId:`cc_${t.claudeSessionId}`,hostSessionId:t.claudeSessionId}:null;n||(n=await e.host.resolveSession()??await e.host.fallbackSession());let{sessionId:o,orientOnly:s}=f2({sessionId:n?.sessionId,claudeSessionId:n?.hostSessionId}),a;try{a=await r.withTokenProvider(e.getToken,()=>r.getPlace(t.placeId))}catch(j){throw new Error(`Place not found or not accessible: ${t.placeId} (${j instanceof Error?j.message:String(j)})`)}let c=$2(a,t.placeId),l=null,u=e.getToken,d=t.displayName,p=s?null:await g2(o);if(p&&p.placeId===t.placeId){l=p.agentId;let j=p.agentToken;u=()=>Promise.resolve(j),d=p.displayName,r.setTokenProvider(u);let de=async()=>{console.error("[gigabuddy] Cached agent token expired, re-minting..."),r.setTokenProvider(e.getToken);let ce=await r.requestAgentToken({displayName:d,sessionId:o,scope:c});j=ce.token,l=ce.agentId,u=()=>Promise.resolve(j),r.setTokenProvider(u),$c({sessionId:o,agentId:ce.agentId,agentToken:j,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(()=>{}),console.error("[gigabuddy] Agent token re-minted successfully")};if((()=>{try{let ce=JSON.parse(atob(j.split(".")[1]));return ce.exp?ce.exp*1e3<Date.now():!1}catch{return!0}})())try{await de()}catch(ce){console.error(`[gigabuddy] Re-mint failed, falling back to human token: ${ce instanceof Error?ce.message:String(ce)}`),r.setTokenProvider(e.getToken),u=e.getToken}$c({sessionId:o,agentId:l??p.agentId,agentToken:j,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(()=>{}),r.setOnTokenExpired(async()=>{try{await de()}catch(ce){throw console.error(`[gigabuddy] Re-mint failed: ${ce instanceof Error?ce.message:String(ce)}`),ce}}),console.error(`[gigabuddy] Reusing cached identity: ${d} (${l})`)}else if(!s&&_2(await e.getToken())){let j=await e.getToken();if(l=w2(j),u=e.getToken,r.setTokenProvider(u),console.error("[gigabuddy] Bearer is already an agent principal \u2014 skipping /api/token/agent mint."),l)try{await r.updateAgentProfile(l,{...t.workdir&&{workdir:t.workdir},...o&&{sessionLabel:o}})}catch{}}else if(s)console.error("[gigabuddy] No resolvable session \u2014 orienting read-only (no identity minted).");else try{let j=await r.requestAgentToken({displayName:t.displayName,sessionId:o,scope:c});l=j.agentId;let de=j.token;u=()=>Promise.resolve(de),j.nickname&&(d=j.nickname),$c({sessionId:o,agentId:l,agentToken:de,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(we=>console.error("[gigabuddy] Failed to cache session:",we)),r.setTokenProvider(u),r.setOnTokenExpired(async()=>{console.error("[gigabuddy] Agent token expired, re-minting...");try{r.setTokenProvider(e.getToken);let we=await r.requestAgentToken({displayName:d,sessionId:o,scope:c});de=we.token,u=()=>Promise.resolve(de),r.setTokenProvider(u),$c({sessionId:o,agentId:we.agentId,agentToken:de,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(()=>{}),console.error("[gigabuddy] Agent token re-minted successfully")}catch(we){throw console.error(`[gigabuddy] Re-mint failed: ${we instanceof Error?we.message:String(we)}`),we}});try{await r.updateAgentProfile(l,{...t.workdir&&{workdir:t.workdir},...o&&{sessionLabel:o}})}catch{}}catch(j){console.error(`[gigabuddy] Agent token failed, using human token: ${j instanceof Error?j.message:String(j)}`)}i.placeId=t.placeId,i.tenancyId=a.tenancyId??null,i.agentId=l,r.setTokenProvider(u);let f=async()=>{if(s)return u();let j=await u();try{let de=JSON.parse(atob(j.split(".")[1]));if(de.exp&&de.exp*1e3<Date.now()){console.error("[gigabuddy] WS token expired, re-minting for reconnect..."),r.setTokenProvider(e.getToken);let we=await r.requestAgentToken({displayName:d,sessionId:o,scope:c});return u=()=>Promise.resolve(we.token),r.setTokenProvider(u),l=we.agentId,$c({sessionId:o,agentId:we.agentId,agentToken:we.token,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(()=>{}),we.token}}catch{}return j},m=e.createAwarenessManager({getToken:f,buildWsUrl:j=>r.buildAwarenessWsUrl(j),user:{displayName:d,canonicalId:l??o}}),h=Vz(m,{getPlaceId:()=>t.placeId,getSponsorTopic:()=>i.sponsorTopic,getLocation:()=>({agentId:l,placeId:t.placeId,placeName:a.name,activityLabel:i.currentActivity?.label})});await h.connect(),await h.subscribe(t.placeId);let y=s?null:b2(await u());y&&(i.sponsorTopic=`sponsor:${y}`,await h.subscribe(i.sponsorTopic));let _=t.workdir??process.cwd(),{owner:$,repo:w,branch:k,...S}=await kf(_),J={displayName:d,canonicalId:l??o,status:"active",typing:!1};$&&(J.owner=$),w&&(J.repo=w),k&&(J.branch=k),S.worktreeId&&(J.worktree=S.worktree,J.worktreeId=S.worktreeId,J.isolated=S.isolated);let F=n?.hostSessionId,P=n?await e.host.readSessionName(n):null;F&&(J.claudeSessionId=F),P&&(J.sessionName=P),J.client=e.host.clientLabel;let se=await G_().catch(()=>null),{hostname:ue,container:ae}=await UP(se);J.host=ae?`${ue} (devcontainer)`:ue,se&&(J.machineId=se),s||h.updateTopicState(t.placeId,J),i.awarenessManager=h,!s&&i.livePageManagerFactory&&(i.livePageManager=i.livePageManagerFactory(h,{name:d,canonicalId:l??o})),i.agentMeta={displayName:d,sessionId:o,claudeSessionId:F,sessionName:P??void 0,placeName:a.name,workdir:t.workdir};let Me=new Cf(i,o,{workspaceSyncer:async j=>{!i.workspaceInstanceId||!i.placeId||await r.updatePlaceContent(i.placeId,i.workspaceInstanceId,j)},profileSyncer:async j=>{l&&await r.updateAgentProfile(l,j)},pageChecker:async(j,de)=>{try{let we=await r.getPlaceContent(j,de),ce=we.instance??we,Tn=ce.data;return{updatedAt:ce.updatedAt??null,lastEditedBy:Tn?.lastEditedBy??null,document:Tn?.document??void 0}}catch{return null}},messageFetcher:async(j,de)=>{try{return(await r.getMessages(j,{limit:50,after:de})).messages.map(ce=>({id:ce.id,content:Lr(ce.content),senderName:ce.senderName,senderCanonicalId:ce.senderCanonicalId,createdAt:ce.createdAt,parentMessageId:ce.parentMessageId,mentionTargets:ce.mentionTargets}))}catch{return null}},changedFetcher:async(j,de)=>{try{return await r.getChangedContent(j,de)}catch{return null}}});i.inboxWriter=Me,Me.start().catch(j=>console.error("[gigabuddy] Inbox writer error:",j)),i.statuslineRenderer?.setPlaceConnected(!0),h.onConnectionChange(j=>i.statuslineRenderer?.setWsConnected(j));let je=new bf;je.onMessage(j=>{if(j.type!=="page.saved"||!j.pageId)return;let de=i.watchedPages.get(j.pageId);i.inboxWriter?.addEvent({type:"page_updated",peer:"human (VS Code)",detail:de?.title??j.pageId})}),je.start(t.placeId),i.bridge=je,!s&&n&&e.host.markConnected(n).catch(()=>{});let ie=JSON.stringify({tenancyId:a.tenancyId??null,orgId:a.orgId??null,placeId:t.placeId,placeName:a.name},null,2);kc(qr(Rt(),"connection.json"),ie).catch(()=>{}),kc(qr(p2(),".gigabuddy","connection.json"),ie).catch(()=>{}),i.connected=!0,i.placeConversationId=a.conversationId??null;let qe=h.getTopicPeers(t.placeId),Ve={messages:[]},We=[],Et=null;try{[Ve,We,Et]=await Promise.all([r.getMessages(t.placeId,{limit:20}),r.listActivities(t.placeId,{status:"active"}),QP(r,t.placeId)])}catch(j){console.error(`[gigabuddy] Warmup calls failed (non-fatal): ${j instanceof Error?j.message:String(j)}`)}if(i.houseRuleHeadlines=Et?ez(Et):null,!s)try{let j=await G_().catch(()=>null),de={display_name:d,owner:$??void 0,repo:w??void 0,branch:k??void 0,status:"active",last_active_at:new Date().toISOString(),claude_session_id:F??void 0,session_name:P??void 0,machine_id:j??void 0,cwd:_},we=await y2(o,t.placeId);if(!we)try{let Tn=((await r.listPlaceContent(t.placeId,{contextSchemaId:Bz,limit:200})).instances??[]).find(Tc=>(Tc.data??{}).session_id===o);Tn?.id&&(we=Tn.id)}catch(ce){console.error(`[gigabuddy] Workspace lookup failed (creating fresh record): ${ce instanceof Error?ce.message:String(ce)}`)}if(we)await r.updatePlaceContent(t.placeId,we,{connected_at:new Date().toISOString(),...de}),i.workspaceInstanceId=we;else{let ce=await r.createPlaceContent(t.placeId,"agent_workspace",{session_id:o,connected_at:new Date().toISOString(),...de},{contextSchemaId:Bz});i.workspaceInstanceId=ce.instance?.id??null}i.workspaceInstanceId?(await v2(o,t.placeId,i.workspaceInstanceId).catch(()=>{}),console.error(`[gigabuddy] Workspace instance: ${i.workspaceInstanceId}`)):console.error("[gigabuddy] Workspace instance NOT persisted (create returned no id)")}catch(j){console.error(`[gigabuddy] Workspace instance write failed (non-fatal): ${j instanceof Error?j.message:String(j)}`)}if(Ve.messages.length>0){let j=Ve.messages[Ve.messages.length-1];j&&(i.lastMessageCursor=j.id)}if(!s&&e.onConnected)try{e.onConnected()}catch(j){console.error(`[gigabuddy] onConnected hook failed (non-fatal): ${j instanceof Error?j.message:j}`)}return{placeName:a.name,placeDescription:a.description?.trim()||null,houseRules:Et,tenancyId:a.tenancyId??null,visibility:a.visibility??null,agentId:l,displayName:d,sessionId:o,peers:qe.map(j=>{let de=j.state;return{name:de.displayName??"Unknown",status:de.status??"unknown",action:de.action?.label,activityId:de.activityId??void 0}}),liveActivities:k2(We,qe),totalActiveActivities:We.length,recentMessages:Ve.messages.slice(-5).map(j=>{let de=Lr(j.content);return{sender:j.senderName??"Unknown",time:j.createdAt?wc(j.createdAt):"",content:de.length>100?de.slice(0,100)+"...":de}}),totalMessages:Ve.messages.length}}function Kz(t,e,r,i){t.tool("list_places","List places you have access to. Use this to discover available places before connecting.",{},async()=>{try{return await e.withTokenProvider(i.getToken,async()=>{let n=await e.listTenancies();if(n.length===0)return{content:[{type:"text",text:"No tenancies found. You may need to be invited to one first."}]};let o=[];for(let s of n){o.push(`Tenancy: ${s.name} (${s.id})`);try{let a=await e.listPlaces(s.id);if(a.length===0)o.push(" No places");else for(let c of a){let l=c.description?` \u2014 ${c.description}`:"",u=c.memberCount?` (${c.memberCount} members)`:"";o.push(` - ${c.name}${u}${l}`),o.push(` id: ${c.id}`)}}catch(a){o.push(` Error listing places: ${a instanceof Error?a.message:String(a)}`)}o.push("")}return{content:[{type:"text",text:o.join(`
|
|
232
|
+
If the user really wants this session in that room, call connect again with confirm: true \u2014 it will be remembered for this repo and not asked again. Check with them first: everything this session posts will land there.`}var Jz="sanctioned-places.json";async function Gz(){try{let t=await Ef(qr(Rt(),Jz),"utf-8"),e=JSON.parse(t);if(Array.isArray(e.places))return e.places.filter(r=>typeof r.placeId=="string")}catch{}try{let t=await Ef(qr(Rt(),"connection.json"),"utf-8"),e=JSON.parse(t);if(e.placeId)return[{placeId:e.placeId,placeName:e.placeName,tenancyId:e.tenancyId}]}catch{}return[]}async function h2(t){let e=(await Gz()).filter(r=>r.placeId!==t.placeId);e.push({...t,sanctionedAt:new Date().toISOString()}),await g_(),await kc(qr(Rt(),Jz),JSON.stringify({places:e},null,2))}async function g2(t){try{let e=await Ef(qr(Je(t),"session.json"),"utf-8");return JSON.parse(e)}catch{return null}}async function $c(t){await Zr(t.sessionId),await kc(qr(Je(t.sessionId),"session.json"),JSON.stringify(t,null,2))}async function y2(t,e){try{let r=await Ef(qr(Je(t),"ws.json"),"utf-8"),i=JSON.parse(r);return i.placeId===e&&i.instanceId?i.instanceId:null}catch{return null}}async function v2(t,e,r){await Zr(t),await kc(qr(Je(t),"ws.json"),JSON.stringify({placeId:e,instanceId:r}))}function b2(t){try{return JSON.parse(atob(t.split(".")[1])).actingAs?.sub??null}catch{return null}}function _2(t){try{return JSON.parse(atob(t.split(".")[1])).principalType==="agent"}catch{return!1}}function w2(t){try{return JSON.parse(atob(t.split(".")[1])).sub??null}catch{return null}}function $2(t,e){return{...t.tenancyId?{tenancyId:t.tenancyId,installationId:t.tenancyId}:{},placeId:e}}function k2(t,e){let r=e.map(c=>c.state),i=c=>r.filter(l=>l.activityId===c).map(l=>l.displayName??"Unknown"),n=c=>c.updatedAt??c.createdAt??"",o=(c,l)=>({id:c.id,label:c.label,peerName:l?i(c.id).join(", "):void 0,updatedAgo:n(c)?wc(n(c)):void 0}),s=t.filter(c=>i(c.id).length>0),a=t.filter(c=>i(c.id).length===0&&n(c)).sort((c,l)=>n(l).localeCompare(n(c)));return[...s.slice(0,10).map(c=>o(c,!0)),...a.map(c=>o(c,!1))].slice(0,10)}async function X_(t,e,r,i){let n=t.sessionId?{sessionId:t.sessionId,hostSessionId:t.claudeSessionId}:t.claudeSessionId?{sessionId:`cc_${t.claudeSessionId}`,hostSessionId:t.claudeSessionId}:null;n||(n=await e.host.resolveSession()??await e.host.fallbackSession());let{sessionId:o,orientOnly:s}=f2({sessionId:n?.sessionId,claudeSessionId:n?.hostSessionId}),a;try{a=await r.withTokenProvider(e.getToken,()=>r.getPlace(t.placeId))}catch(j){throw new Error(`Place not found or not accessible: ${t.placeId} (${j instanceof Error?j.message:String(j)})`)}let c=$2(a,t.placeId),l=null,u=e.getToken,d=t.displayName,p=s?null:await g2(o);if(p&&p.placeId===t.placeId){l=p.agentId;let j=p.agentToken;u=()=>Promise.resolve(j),d=p.displayName,r.setTokenProvider(u);let de=async()=>{console.error("[gigabuddy] Cached agent token expired, re-minting..."),r.setTokenProvider(e.getToken);let ce=await r.requestAgentToken({displayName:d,sessionId:o,scope:c});j=ce.token,l=ce.agentId,u=()=>Promise.resolve(j),r.setTokenProvider(u),$c({sessionId:o,agentId:ce.agentId,agentToken:j,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(()=>{}),console.error("[gigabuddy] Agent token re-minted successfully")};if((()=>{try{let ce=JSON.parse(atob(j.split(".")[1]));return ce.exp?ce.exp*1e3<Date.now():!1}catch{return!0}})())try{await de()}catch(ce){console.error(`[gigabuddy] Re-mint failed, falling back to human token: ${ce instanceof Error?ce.message:String(ce)}`),r.setTokenProvider(e.getToken),u=e.getToken}$c({sessionId:o,agentId:l??p.agentId,agentToken:j,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(()=>{}),r.setOnTokenExpired(async()=>{try{await de()}catch(ce){throw console.error(`[gigabuddy] Re-mint failed: ${ce instanceof Error?ce.message:String(ce)}`),ce}}),console.error(`[gigabuddy] Reusing cached identity: ${d} (${l})`)}else if(!s&&_2(await e.getToken())){let j=await e.getToken();if(l=w2(j),u=e.getToken,r.setTokenProvider(u),console.error("[gigabuddy] Bearer is already an agent principal \u2014 skipping /api/token/agent mint."),l)try{await r.updateAgentProfile(l,{...t.workdir&&{workdir:t.workdir},...o&&{sessionLabel:o}})}catch{}}else if(s)console.error("[gigabuddy] No resolvable session \u2014 orienting read-only (no identity minted).");else try{let j=await r.requestAgentToken({displayName:t.displayName,sessionId:o,scope:c});l=j.agentId;let de=j.token;u=()=>Promise.resolve(de),j.nickname&&(d=j.nickname),$c({sessionId:o,agentId:l,agentToken:de,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(we=>console.error("[gigabuddy] Failed to cache session:",we)),r.setTokenProvider(u),r.setOnTokenExpired(async()=>{console.error("[gigabuddy] Agent token expired, re-minting...");try{r.setTokenProvider(e.getToken);let we=await r.requestAgentToken({displayName:d,sessionId:o,scope:c});de=we.token,u=()=>Promise.resolve(de),r.setTokenProvider(u),$c({sessionId:o,agentId:we.agentId,agentToken:de,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(()=>{}),console.error("[gigabuddy] Agent token re-minted successfully")}catch(we){throw console.error(`[gigabuddy] Re-mint failed: ${we instanceof Error?we.message:String(we)}`),we}});try{await r.updateAgentProfile(l,{...t.workdir&&{workdir:t.workdir},...o&&{sessionLabel:o}})}catch{}}catch(j){console.error(`[gigabuddy] Agent token failed, using human token: ${j instanceof Error?j.message:String(j)}`)}i.placeId=t.placeId,i.tenancyId=a.tenancyId??null,i.agentId=l,r.setTokenProvider(u);let f=async()=>{if(s)return u();let j=await u();try{let de=JSON.parse(atob(j.split(".")[1]));if(de.exp&&de.exp*1e3<Date.now()){console.error("[gigabuddy] WS token expired, re-minting for reconnect..."),r.setTokenProvider(e.getToken);let we=await r.requestAgentToken({displayName:d,sessionId:o,scope:c});return u=()=>Promise.resolve(we.token),r.setTokenProvider(u),l=we.agentId,$c({sessionId:o,agentId:we.agentId,agentToken:we.token,displayName:d,placeId:t.placeId,savedAt:new Date().toISOString()}).catch(()=>{}),we.token}}catch{}return j},m=e.createAwarenessManager({getToken:f,buildWsUrl:j=>r.buildAwarenessWsUrl(j),user:{displayName:d,canonicalId:l??o}}),h=Vz(m,{getPlaceId:()=>t.placeId,getSponsorTopic:()=>i.sponsorTopic,getLocation:()=>({agentId:l,placeId:t.placeId,placeName:a.name,activityLabel:i.currentActivity?.label})});await h.connect(),await h.subscribe(t.placeId);let y=s?null:b2(await u());y&&(i.sponsorTopic=`sponsor:${y}`,await h.subscribe(i.sponsorTopic));let _=t.workdir??process.cwd(),{owner:$,repo:w,branch:k,...S}=await kf(_),J={displayName:d,canonicalId:l??o,status:"active",typing:!1};$&&(J.owner=$),w&&(J.repo=w),k&&(J.branch=k),S.worktreeId&&(J.worktree=S.worktree,J.worktreeId=S.worktreeId,J.isolated=S.isolated);let F=n?.hostSessionId,P=n?await e.host.readSessionName(n):null;F&&(J.claudeSessionId=F),P&&(J.sessionName=P),J.client=e.host.clientLabel;let se=await G_().catch(()=>null),{hostname:ue,container:ae}=await UP(se);J.host=ae?`${ue} (devcontainer)`:ue,se&&(J.machineId=se),s||h.updateTopicState(t.placeId,J),i.awarenessManager=h,!s&&i.livePageManagerFactory&&(i.livePageManager=i.livePageManagerFactory(h,{name:d,canonicalId:l??o})),i.agentMeta={displayName:d,sessionId:o,claudeSessionId:F,sessionName:P??void 0,placeName:a.name,workdir:t.workdir};let Me=new Cf(i,o,{workspaceSyncer:async j=>{!i.workspaceInstanceId||!i.placeId||await r.updatePlaceContent(i.placeId,i.workspaceInstanceId,j)},profileSyncer:async j=>{l&&await r.updateAgentProfile(l,j)},pageChecker:async(j,de)=>{try{let we=await r.getPlaceContent(j,de),ce=we.instance??we,Tn=ce.data;return{updatedAt:ce.updatedAt??null,lastEditedBy:Tn?.lastEditedBy??null,document:Tn?.document??void 0}}catch{return null}},messageFetcher:async(j,de)=>{try{return(await r.getMessages(j,{limit:50,after:de})).messages.map(ce=>({id:ce.id,content:Lr(ce.content),senderName:ce.senderName,senderCanonicalId:ce.senderCanonicalId,createdAt:ce.createdAt,parentMessageId:ce.parentMessageId,mentionTargets:ce.mentionTargets}))}catch{return null}},changedFetcher:async(j,de)=>{try{return await r.getChangedContent(j,de)}catch{return null}}});i.inboxWriter=Me,Me.start().catch(j=>console.error("[gigabuddy] Inbox writer error:",j)),i.statuslineRenderer?.setPlaceConnected(!0),h.onConnectionChange(j=>i.statuslineRenderer?.setWsConnected(j));let je=new bf;je.onMessage(j=>{if(j.type!=="page.saved"||!j.pageId)return;let de=i.watchedPages.get(j.pageId);i.inboxWriter?.addEvent({type:"page_updated",peer:"human (VS Code)",detail:de?.title??j.pageId})}),je.start(t.placeId),i.bridge=je,!s&&n&&e.host.markConnected(n).catch(()=>{});let ie=JSON.stringify({tenancyId:a.tenancyId??null,orgId:a.orgId??null,placeId:t.placeId,placeName:a.name},null,2);kc(qr(Rt(),"connection.json"),ie).catch(()=>{}),kc(qr(p2(),".gigabuddy","connection.json"),ie).catch(()=>{}),i.connected=!0,i.placeConversationId=a.conversationId??null;let qe=h.getTopicPeers(t.placeId),Ve={messages:[]},We=[],Et=null;try{[Ve,We,Et]=await Promise.all([r.getMessages(t.placeId,{limit:20}),r.listActivities(t.placeId,{status:"active"}),QP(r,t.placeId)])}catch(j){console.error(`[gigabuddy] Warmup calls failed (non-fatal): ${j instanceof Error?j.message:String(j)}`)}if(i.houseRuleHeadlines=Et?ez(Et):null,!s)try{let j=await G_().catch(()=>null),de={display_name:d,owner:$??void 0,repo:w??void 0,branch:k??void 0,status:"active",last_active_at:new Date().toISOString(),claude_session_id:F??void 0,session_name:P??void 0,machine_id:j??void 0,cwd:_},we=await y2(o,t.placeId);if(!we)try{let Tn=((await r.listPlaceContent(t.placeId,{contextSchemaId:Bz,limit:200})).instances??[]).find(Tc=>(Tc.data??{}).session_id===o);Tn?.id&&(we=Tn.id)}catch(ce){console.error(`[gigabuddy] Workspace lookup failed (creating fresh record): ${ce instanceof Error?ce.message:String(ce)}`)}if(we)await r.updatePlaceContent(t.placeId,we,{connected_at:new Date().toISOString(),...de}),i.workspaceInstanceId=we;else{let ce=await r.createPlaceContent(t.placeId,"agent_workspace",{session_id:o,connected_at:new Date().toISOString(),...de},{contextSchemaId:Bz});i.workspaceInstanceId=ce.instance?.id??null}i.workspaceInstanceId?(await v2(o,t.placeId,i.workspaceInstanceId).catch(()=>{}),console.error(`[gigabuddy] Workspace instance: ${i.workspaceInstanceId}`)):console.error("[gigabuddy] Workspace instance NOT persisted (create returned no id)")}catch(j){console.error(`[gigabuddy] Workspace instance write failed (non-fatal): ${j instanceof Error?j.message:String(j)}`)}if(Ve.messages.length>0){let j=Ve.messages[Ve.messages.length-1];j&&(i.lastMessageCursor=j.id)}if(!s&&e.onConnected)try{e.onConnected()}catch(j){console.error(`[gigabuddy] onConnected hook failed (non-fatal): ${j instanceof Error?j.message:j}`)}return{placeName:a.name,placeDescription:a.description?.trim()||null,houseRules:Et,tenancyId:a.tenancyId??null,visibility:a.visibility??null,agentId:l,displayName:d,sessionId:o,peers:qe.map(j=>{let de=j.state;return{name:de.displayName??"Unknown",status:de.status??"unknown",action:de.action?.label,activityId:de.activityId??void 0}}),liveActivities:k2(We,qe),totalActiveActivities:We.length,recentMessages:Ve.messages.slice(-5).map(j=>{let de=Lr(j.content);return{sender:j.senderName??"Unknown",time:j.createdAt?wc(j.createdAt):"",content:de.length>100?de.slice(0,100)+"...":de}}),totalMessages:Ve.messages.length}}function Kz(t,e,r,i){t.tool("list_places","List places you have access to. Use this to discover available places before connecting.",{},async()=>{try{return await e.withTokenProvider(i.getToken,async()=>{let n=await e.listTenancies();if(n.length===0)return{content:[{type:"text",text:"Sorry \u2014 you're not a member of a Gigabuddy club yet. Join the waitlist at gigabuddy.com, or ask a club admin for an invite."}]};let o=[];for(let s of n){o.push(`Tenancy: ${s.name} (${s.id})`);try{let a=await e.listPlaces(s.id);if(a.length===0)o.push(" No places");else for(let c of a){let l=c.description?` \u2014 ${c.description}`:"",u=c.memberCount?` (${c.memberCount} members)`:"";o.push(` - ${c.name}${u}${l}`),o.push(` id: ${c.id}`)}}catch(a){o.push(` Error listing places: ${a instanceof Error?a.message:String(a)}`)}o.push("")}return{content:[{type:"text",text:o.join(`
|
|
233
233
|
`)}]}})}catch(n){return{content:[{type:"text",text:`Failed to list places: ${n instanceof Error?n.message:String(n)}`}],isError:!0}}}),t.tool("open_browser_session","Open an interactive BROWSER session as yourself (this agent) so you can drive Gigabuddy or the chat-app in a real browser (e.g. via Playwright) \u2014 logged in as your own agent identity, with your human sponsor attached. Returns a one-time, short-lived URL to navigate to. You must `connect` to a place first (that establishes your identity).",{app:H.enum([ot().webAppKey,"chat-app"]).optional().describe(`Which web app to open (default: ${ot().webAppKey})`),placeId:H.string().optional().describe("Place to open after sign-in (defaults to your connected place)"),baseUrl:H.string().optional().describe("Override the app base URL for local dev / staging, e.g. http://localhost:3012")},async n=>{try{if(!r.connected||!r.agentId)return{content:[{type:"text",text:"Connect to a place first (use `connect`) \u2014 your agent identity is established on connect."}],isError:!0};let o=await i.getToken(),s=await e.requestBrowserSession(o,{agentId:r.agentId,app:n.app??ot().webAppKey,placeId:n.placeId??r.placeId??void 0,baseUrl:n.baseUrl});return{content:[{type:"text",text:`Browser session ready for ${s.nickname??s.displayName??r.agentId} (expires ${qz(s.expiresAt)}). Open this one-time link:
|
|
234
234
|
|
|
235
235
|
${s.ticketUrl}
|
|
236
236
|
|
|
237
|
-
It signs the browser in as your agent identity with your sponsor attached. The link is single-use \u2014 re-call open_browser_session for a fresh one.`}]}}catch(o){return{content:[{type:"text",text:`Failed to open browser session: ${o instanceof Error?o.message:String(o)}`}],isError:!0}}}),t.tool("connect","Join a place. Pass a placeId to connect directly, or omit it to see available places. Bootstraps awareness and fetches recent messages and activities. SUBAGENTS: if you are a subagent (spawned inside another session via the Agent/Task tool), do not connect \u2014 the parent session owns place presence and posting; return your results to your orchestrator.",{placeId:H.string().optional().describe("Place ID to join (omit to list available places)"),confirm:H.boolean().optional().describe("Required the FIRST time this repo connects to a given room (sanctioned rooms are remembered and never re-ask). Only pass true after checking with the user \u2014 this is the guard against posting work into the wrong room."),displayName:H.string().describe("Your display name in the place"),sessionId:H.string().optional().describe("Unique session identifier (defaults to a generated ID)"),workdir:H.string().optional().describe("Current working directory (shown to other agents)")},async n=>{try{if(r.connected)return{content:[{type:"text",text:`Already connected to place ${r.placeId} as ${r.agentMeta?.displayName}. Call disconnect first to reconnect.`}]};if(!n.placeId)return await e.withTokenProvider(i.getToken,async()=>{let a=await e.listTenancies();if(a.length===0)return{content:[{type:"text",text:"
|
|
237
|
+
It signs the browser in as your agent identity with your sponsor attached. The link is single-use \u2014 re-call open_browser_session for a fresh one.`}]}}catch(o){return{content:[{type:"text",text:`Failed to open browser session: ${o instanceof Error?o.message:String(o)}`}],isError:!0}}}),t.tool("connect","Join a place. Pass a placeId to connect directly, or omit it to see available places. Bootstraps awareness and fetches recent messages and activities. SUBAGENTS: if you are a subagent (spawned inside another session via the Agent/Task tool), do not connect \u2014 the parent session owns place presence and posting; return your results to your orchestrator.",{placeId:H.string().optional().describe("Place ID to join (omit to list available places)"),confirm:H.boolean().optional().describe("Required the FIRST time this repo connects to a given room (sanctioned rooms are remembered and never re-ask). Only pass true after checking with the user \u2014 this is the guard against posting work into the wrong room."),displayName:H.string().describe("Your display name in the place"),sessionId:H.string().optional().describe("Unique session identifier (defaults to a generated ID)"),workdir:H.string().optional().describe("Current working directory (shown to other agents)")},async n=>{try{if(r.connected)return{content:[{type:"text",text:`Already connected to place ${r.placeId} as ${r.agentMeta?.displayName}. Call disconnect first to reconnect.`}]};if(!n.placeId)return await e.withTokenProvider(i.getToken,async()=>{let a=await e.listTenancies();if(a.length===0)return{content:[{type:"text",text:"Sorry \u2014 you're not a member of a Gigabuddy club yet. Join the waitlist at gigabuddy.com, or ask a club admin for an invite."}]};let c=["No placeId specified. Available places:",""];for(let l of a)try{let u=await e.listPlaces(l.id);for(let d of u)c.push(` - ${d.name} (${d.id})`)}catch{}return c.push(""),c.push("Call connect again with a placeId to join one."),{content:[{type:"text",text:c.join(`
|
|
238
238
|
`)}]}});if(!n.confirm){let a=await Gz();if(!a.some(c=>c.placeId===n.placeId)){let c=await e.withTokenProvider(i.getToken,async()=>{let l=await e.getPlace(n.placeId),u=await e.listTenancies();return m2(a,{...l,id:n.placeId},u)});if(c)return{content:[{type:"text",text:c}],isError:!0}}}let o=await X_({placeId:n.placeId,displayName:n.displayName,sessionId:n.sessionId,workdir:n.workdir},i,e,r);await h2({placeId:n.placeId,placeName:o.placeName,tenancyId:o.tenancyId}).catch(()=>{});let s=[];if(s.push(`Connected to "${o.placeName}" (${n.placeId})`),o.tenancyId&&s.push(` Club (tenancy): ${o.tenancyId}`),o.visibility&&s.push(o.visibility==="public"?" Visibility: PUBLIC \u2014 anyone who can see this club can read what you post here":` Visibility: ${o.visibility}`),o.agentId&&s.push(` Agent ID: ${o.agentId}`),s.push(` Display name: ${o.displayName}`),s.push(` Agents online: ${o.peers.length}`),s.push(""),o.placeDescription&&(s.push(`About this place: ${o.placeDescription}`),s.push("")),o.houseRules?.unreadable)s.push("\u26A0 House rules unreadable this session \u2014 do not assume there are none."),s.push("");else if(o.houseRules&&o.houseRules.rules.length>0){s.push("House rules here (standing directives \u2014 they outrank ad-hoc instructions):");for(let a of o.houseRules.rules){let c=a.pageRefs.length>0?` \u2014 read before proceeding: ${a.pageRefs.join(", ")}`:"";s.push(` \u25B8 ${a.title}${a.firmness==="memory"?" (advisory)":""}${c}`)}s.push("")}if(o.peers.length>0){s.push("Connected agents:");for(let a of o.peers)s.push(` - ${a.name} (${a.status}${a.action?`: ${a.action}`:""})`);s.push("")}if(o.liveActivities.length>0){s.push(`Recent activities (${o.liveActivities.length} of ${o.totalActiveActivities} active):`);for(let a of o.liveActivities){let c=a.peerName?` \u2014 ${a.peerName} is on it now`:a.updatedAgo?` (updated ${a.updatedAgo})`:"";s.push(` - [${a.id}] ${a.label}${c}`)}s.push(" (get_activities browses the rest)"),s.push("")}else o.totalActiveActivities>0&&(s.push(`Active activities: ${o.totalActiveActivities} (get_activities browses them)`),s.push(""));if(o.recentMessages.length>0){s.push(`Recent messages (${o.totalMessages}):`);for(let a of o.recentMessages)s.push(` [${a.time}] ${a.sender}: ${a.content}`);o.totalMessages>5&&s.push(` (${o.totalMessages-5} more \u2014 use get_messages to read all)`)}try{let a=await e.listMyAsks({status:"open",limit:10}),c=a.asks??[];if(c.length>0){s.push(""),s.push(`\u{1F4E8} ${a.count} open ask(s) addressed to you (delivered while you were away or still unanswered):`);for(let l of c.slice(0,5)){let u=l.data??{},d=(u.raisedBy??{}).name,p=u.target??{},f=typeof p.id=="string"&&p.id?` \xB7 about ${typeof p.label=="string"&&p.label?`"${p.label}" `:""}${p.id}`:"";s.push(` - ${typeof u.title=="string"?u.title:"(untitled)"}${typeof u.urgency=="string"?` [${u.urgency}]`:""}${typeof d=="string"?` \u2014 from ${d}`:""}${f} (${l.id})`)}a.count>5&&s.push(` (${a.count-5} more \u2014 list_asks for the full queue)`),s.push(" Answer with answer(<id>), commit with ack(<id>), or defer with snooze_ask.")}}catch{}return{content:[{type:"text",text:s.join(`
|
|
239
239
|
`)}]}}catch(o){return e.setTokenProvider(i.getToken),r.reset(),{content:[{type:"text",text:`Failed to connect: ${o instanceof Error?o.message:String(o)}`}],isError:!0}}}),t.tool("disconnect","Leave the current place. Completes any active activity (a handover work-session is handed back and left claimable instead of completed) and cleans up awareness.",{},async()=>{if(!r.connected)return r.autoConnectSuppressed=!0,r.statuslineRenderer?.setPendingPlace(null),{content:[{type:"text",text:"Not connected \u2014 auto-connect disabled for this session. Use `connect` to join a place."}]};r.autoConnectSuppressed=!0;try{if(r.currentActivity&&r.placeId){let n=r.currentActivity.activityId,o=await Rf(e,r.placeId,n).catch(()=>null);if(o){let s=r.agentId!=null&&r.agentId===o.originActorId;if(await e.setMyStatus(r.placeId,n,{status:"handed-off",actorType:"buddy"}).catch(()=>{}),!s&&o.workItemId&&await K_(e,r.placeId,o.workItemId),s&&o.pageId&&o.handover){let a=o.handover.origin??{};await e.updatePlaceContent(r.placeId,o.pageId,{handover:{...o.handover,origin:{...a,until:new Date().toISOString()}}}).catch(()=>{})}r.clearOfficeHoursForActivity(n)}else try{await e.completeActivity(r.placeId,n)}catch{}r.clearCurrentActivity()}if(r.inboxWriter?.stop(),r.workspaceInstanceId&&r.placeId)try{await e.updatePlaceContent(r.placeId,r.workspaceInstanceId,{status:"disconnected",last_active_at:new Date().toISOString()})}catch{}return r.awarenessManager?.disconnect(),e.setTokenProvider(i.getToken),r.reset(),{content:[{type:"text",text:"Disconnected."}]}}catch(n){return{content:[{type:"text",text:`Error during disconnect: ${n instanceof Error?n.message:String(n)}`}],isError:!0}}})}function Qz(t,e,r){let i=new of,n=new Kp({name:ot().serverName,version:t.version??"0.0.0"}),o=t.host??(t.externalSessionId?new pf(t.externalSessionId):new df),s=new af(n,e,i,{version:t.version}),a={getToken:t.getToken,apiUrl:t.apiUrl,authUrl:t.authUrl,host:o,onConnected:()=>s.activate(),createAwarenessManager:l=>new Lo(l)},c={...t.auth,onLogin:l=>{t.auth.onLogin(l),i.statuslineRenderer?.setSignedIn(!0)}};return r(n,e,i,{connectConfig:a,auth:c}),{server:n,client:e,state:i,async listen(){let l=new Yp;await n.connect(l),console.error("Gigabuddy agent server started"),kP().then(f=>{f>0&&console.error(`[gigabuddy] Cleaned up ${f} stale file(s)`)}).catch(()=>{});let u=await S2(),d=(f,m)=>{let h=new vf(f);return h.setSignedIn(t.auth.isAuthenticated()),i.statuslineRenderer=h,h.start().catch(y=>console.error("[gigabuddy] statusline renderer error:",y)),t.auth.isAuthenticated()&&(async()=>{let y=t.autoConnect?.placeId?{kind:"default",placeId:t.autoConnect.placeId}:Xz(u,m);if(y.kind!=="resume"&&y.kind!=="default")return;let _=y.placeId,$=null;try{let w=await Yz(xc(Rt(),"connection.json"),"utf-8"),k=JSON.parse(w);k.placeId===_&&k.placeName&&($=k.placeName)}catch{}h.setPendingPlace($??_)})(),h},p=async()=>{if(i.statuslineRenderer)return;let f=await o.resolveSession().catch(()=>null);if(f){console.error(`[gigabuddy] Host session resolved (${o.clientLabel}): ${f.sessionId}`);let h=o.statuslineRef(f);h&&d(h,f.sessionId);return}setTimeout(()=>void p(),z2).unref?.()};p(),t.auth.isAuthenticated()?(t.autoConnect||u.length>0)&&E2(o,m=>{if(t.autoConnect)return t.autoConnect;let h=Xz(u,m.sessionId);return h.kind==="resume"||h.kind==="default"?(console.error(h.kind==="resume"?`[gigabuddy] Resuming into this session's own place ${h.placeId}`:`[gigabuddy] Defaulting to this host's single known place ${h.placeId}`),{placeId:h.placeId}):h.kind==="ambiguous"?{ambiguous:h.placeIds}:null},a,e,i):console.error("[gigabuddy] Not signed in \u2014 call the `login` tool to authenticate. Skipping auto-connect."),R2(process,()=>{i.inboxWriter?.stop(),i.statuslineRenderer?.stop(),i.awarenessManager?.disconnect()})}}}async function S2(){try{let t=await Y_(ar()),e=[];for(let r of t){let i,n,o=xc(ar(),r);try{if((await x2(o)).isDirectory())i=xc(o,"session.json"),n=r;else{if(!r.endsWith(".json")||r.startsWith("ws-"))continue;i=o,n=r.slice(0,-5)}}catch{continue}try{let s=await Yz(i,"utf-8"),a=JSON.parse(s);if(!a.placeId)continue;e.push({sessionId:n,placeId:a.placeId,savedAt:a.savedAt??""})}catch{}}return e}catch{return[]}}function Xz(t,e){let r=t.find(o=>o.sessionId===e);if(r)return{kind:"resume",placeId:r.placeId};let i=new Map;for(let o of t){let s=i.get(o.placeId);(s===void 0||o.savedAt>s)&&i.set(o.placeId,o.savedAt)}return i.size===0?{kind:"none"}:i.size===1?{kind:"default",placeId:[...i.keys()][0]}:{kind:"ambiguous",placeIds:[...i.entries()].sort(([,o],[,s])=>o<s?1:-1).map(([o])=>o)}}var I2=500,T2=5e3,P2=3e5,z2=1e4;function C2(t){return t<P2?I2:T2}function R2(t,e){let r=!1,i=()=>{r||(r=!0,e())},n=()=>{i(),t.exit(0)};t.on("SIGTERM",n),t.on("SIGINT",n),t.on("exit",i),t.stdin.on("end",n),t.stdin.on("close",n)}function E2(t,e,r,i,n){let o=Date.now(),s=!1,a=!1,c=!1,l=async()=>{let{stat:d,unlink:p}=await import("node:fs/promises");try{let _=[];try{for(let k of await Y_(ar()))_.push(xc(ar(),k,"pending-connect.json"))}catch{}for(let k of await Y_(Rt()))k.startsWith("pending-connect-")&&k.endsWith(".json")&&_.push(xc(Rt(),k));let $=0,w=[];for(let k of _)try{let S=await d(k);$++,S.mtimeMs<o&&w.push(k)}catch{}if($===0||w.length>0&&(await Promise.all(w.map(k=>p(k).catch(()=>{}))),w.length===$))return}catch{return}let f=await t.resolveSession().catch(()=>null),m="resolver";if(f){if(!await t.consumeConnectTrigger(f))return}else{if(f=await t.fallbackSession(),!f)return;m="fallback",await t.consumeConnectTrigger(f)}let h=e(f);if(h===null){a=!0;return}if("ambiguous"in h){n.autoConnectAmbiguity=h.ambiguous,a=!0,console.error(`[gigabuddy] Auto-connect skipped: recent sessions on this host used different places (${h.ambiguous.join(", ")}) and this session has none of its own yet \u2014 refusing to guess. Use the \`connect\` tool to pick one.`);return}console.error(`[gigabuddy] Identity via ${m} (${t.clientLabel}): ${f.sessionId}`);let y=await X_({placeId:h.placeId,displayName:h.displayName??t.defaultDisplayName,sessionId:f.sessionId,workdir:process.cwd(),claudeSessionId:f.hostSessionId},r,i,n);s=!0,console.error(`[gigabuddy] Connected to "${y.placeName}" as ${y.displayName} (session: ${f.sessionId})`),y.peers.length>0&&console.error(`[gigabuddy] Peers online: ${y.peers.map(_=>_.name).join(", ")}`)},u=async()=>{if(s||a||c||n.autoConnectSuppressed)return;c=!0;try{await l()}catch(p){console.error(`[gigabuddy] Auto-connect error: ${p instanceof Error?p.message:String(p)}`)}finally{c=!1}if(s||a||n.autoConnectSuppressed)return;setTimeout(u,C2(Date.now()-o)).unref?.()};u()}var Sc="agent";function Af(t=!1){return Gf(t,Sc)}function Q_(t,e=!1){Kf(t,e,Sc)}function ew(t=!1){Ew(t,Sc)}function tw(t=!1){return Yo(t,Sc)}function eC(t,e=!1){Aw(t,e,Sc)}var A2=["agent:spawn","discovery:read"];async function Of(t){return BT({authUrl:t,clientId:"gigabuddy-agent",scopes:A2})}async function Nf(t,e,r={}){return JT(t,e,{onPending:r.onPoll})}function fi(t){return{content:[{type:"text",text:t}]}}function tC(t,e){let r=null;t.tool("login","Sign in to Gigabuddy (one-time). Call this when a tool reports you are not authenticated. It returns a URL and a short code for the user to approve in their browser; relay them verbatim. Authentication completes in the background \u2014 re-call `login` to confirm, then retry what you were doing.",{},async()=>{if(e.isAuthenticated()){let n=e.currentUser();return fi(`Already signed in${n?` as ${n}`:""}. No action needed.`)}if(r?.status==="complete"){let n=e.currentUser();return r=null,fi(`Signed in${n?` as ${n}`:""} \u2713 You can use the other Gigabuddy tools now.`)}if(r?.status==="error"){let n=r.error??"unknown error";return r=null,fi(`The previous sign-in attempt failed (${n}). Call \`login\` again to retry.`)}if(r?.status==="pending"&&Date.now()<r.deadline)return fi(`Still waiting for approval. Visit ${r.flow.verificationUrl} and enter code ${r.flow.userCode}, then re-call \`login\` to confirm.`);let i=await Of(e.authUrl);return r={flow:i,deadline:Date.now()+i.expiresIn*1e3,status:"pending"},uc(i.verificationUrl).catch(()=>{}),Nf(e.authUrl,i).then(n=>{e.onLogin({refreshToken:n.refreshToken,userId:n.userId,userEmail:n.userEmail,authUrl:e.authUrl,apiUrl:e.apiUrl,createdAt:new Date().toISOString()}),r?.flow===i&&(r.status="complete")}).catch(n=>{r?.flow===i&&(r.status="error",r.error=n instanceof Error?n.message:String(n))}),fi(`To connect Gigabuddy, the user needs to sign in (one time):
|
|
240
240
|
|
package/package.json
CHANGED